如何杀死/结束/取消/加入套接字阻止线程?

I have made a thread which is able to read bluetooth messages sent from phone. My problem came when I realised I have no way of killing that thread safely. Method so far was user input which called exit() from within that thread, all weird stuff started happening when I moved that out of that thread and into the main (stack smashing detected and segmentation fault). Obviously this approach also wouldn't really scale well if I had another thread for wifi calls or just didn't want to exit everything altogether.

到目前为止,这是我的代码。

将蓝牙相关内容传递给线程的结构:

typedef struct {
    struct sockaddr_rc loc_addr;
    struct sockaddr_rc rem_addr;
    socklen_t opt;
    char blu_buffer[1024];
    int blu_sock;    
} Bluetooth_stuff;

线程监听新连接:

void * BluetoothListiner(void * argv){

    Bluetooth_stuff * bt_set = (Bluetooth_stuff * ) argv;

    int bytes_read;
    int local_client;   
    int option = 0; 

    listen(bt_set->blu_sock, 1);
    memset(bt_set->blu_buffer, 0, sizeof(bt_set->blu_buffer));

    while(true){

        local_client = accept(bt_set->blu_sock, (struct sockaddr *)&((*bt_set).rem_addr), &((*bt_set).opt));        

        // read data from the client
        bytes_read = read(local_client, bt_set->blu_buffer, sizeof(bt_set->blu_buffer));
        if( bytes_read > 0 ) {
            // process data
            }   
        }
        else{
            // accept again?
        }       

        // clear the buffer
        memset(bt_set->blu_buffer, 0, sizeof(bt_set->blu_buffer));

        // close connection
        close(local_client);

        usleep(10);
    }
}

套接字配置:

void BluetoothSocketConfig(Bluetooth_stuff * bt_set){   

    // allocate socket
    bt_set->blu_sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);        
    bt_set->opt= sizeof(bt_set->rem_addr);

    (*bt_set).loc_addr.rc_family = AF_BLUETOOTH;
    (*bt_set).loc_addr.rc_bdaddr = *BDADDR_ANY;
    (*bt_set).loc_addr.rc_channel = (uint8_t) 1;        

    // bind socket to port 1 of the first available 
    bind(bt_set->blu_sock, (struct sockaddr *)&(bt_set->loc_addr), sizeof(bt_set->loc_addr));

}

测试主要:

int main(int argc, char *argv[]){       
    Bluetooth_stuff bt_set;     
    BluetoothSocketConfig(&bt_set);     
    pthread_create(&blu_listiner, NULL, BluetoothListiner, bt_set);
    while(1);  // I modify that for testing to exit, having a global flag also gave me segmentation errors somehow
}

Calling exit(1) doesn't clean up other threads and pthread_kill or pthread_cancel from another thread would often cause processes still running in the background preventing me from running the application again without manually killing processes with ps -A and kill -9 PROCESS.

Based on this article I figured that the best way to do that was to introduce an if statement within the thread and have it pthread_exit itself into the oblivion. Such as:

if(external_exit){
    ret2  = 200;
    pthread_exit(&ret2);
}

Now since read() is a blocking call, I could never arrive at if statement without something externally happening. This answer suggests using a timeout to achieve that and I followed the syntax from this answer to manage to break out from read() after a certain period. So I had this added before the main while loop of the thread ( i think this should only be defined once rather than at every loop, though not sure as couldn't find specific example).

Now my problem was that it would block on read() on the first loop, but then would skip it as if nothing and just loop indefinitely. I have tried to "reenable read()", by reinvoking accept() listen() and bind() with no success. It seems using select() is the preferred option for first checking if there is anything to read, but as stated in the manual

“在Linux下,select()可能将套接字文件描述符报告为“就绪        读取”,尽管如此,随后的读取仍会阻塞。        例如可能在数据到达但经过检查时发生        校验和有误并被丢弃”

So even if using it (which I'm not sure would work on bluetooth sockets as it would on tcp ones) there is always a chance it would still get stuck on read() with no way of killing it safely.

1) How can I safely kill that thread (or any blocking thread)?
2) Is select() really needed for blocking approach as I do not have multiple connections?
3) What is the procedure to reenable proper use of read() in blocking mode after the initial timeout?
4) Besides different initialisation are all sockets basically equivalent unix/can/tcp/bluetooth?
5) Any other ways to get what I want or serious flaws in logic from my part?

谢谢您提供的任何帮助,如果有人链接到蓝牙服务器线程实现,我很高兴看到它(或任何其他套接字unix / can / tcp)。

评论