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

问题描述 投票:4回答:1

我制作了一个线程,可以读取从手机发送的蓝牙消息。当我意识到我无法安全地杀死该线程时,我的问题就来了。到目前为止,方法是用户输入从该线程中调用exit(),当我将其移出该线程并移入主线程时,所有奇怪的东西开始发生(检测到堆栈粉碎和分段错误)。显然,如果我有另一个线程进行wifi通话,或者只是不想完全退出所有内容,这种方法也无法很好地扩展。

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

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

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
}

调用exit(1)不会清除其他线程,并且从另一个线程中清除pthread_killpthread_cancel通常会导致进程仍在后台运行,从而使我无法再次运行该应用程序,而无需使用ps -A和[ C0]。

基于此kill -9 PROCESS,我认为最好的方法是在线程内引入article语句,并将其if本身放到遗忘中。如:

pthread_exit

现在,由于if(external_exit){ ret2 = 200; pthread_exit(&ret2); } 是一个阻塞调用,如果没有外部事件,我将永远无法到达read()语句。此if建议使用超时来实现这一目标,我遵循此answer的语法在一段时间后设法从answer突破。所以我在线程的主while循环之前添加了这个(我认为这应该只定义一次,而不是在每个循环中定义,尽管不确定,因为找不到具体的示例)。

现在我的问题是,它将在第一个循环上阻塞read(),但随后会跳过它,就好像什么也没有,只是无限期地循环。我试图通过重新调用read() read()accept()来“重新启用listen()”,但没有成功。似乎首选使用bind()作为首选检查选项,但如手册中所述

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

因此,即使使用它(我不确定它是否可以像在TCP插座上那样在蓝牙插座上工作),也总是有机会仍然卡在select()上而无法安全地将其杀死。

1)如何安全地杀死该线程(或任何阻塞线程)?2)因为我没有多个连接,所以真的需要read()来阻止方法吗?3)在初始超时后,如何在阻止模式下重新启用select()的正确使用的程序是什么?4)除了不同的初始化之外,所有套接字基本上都等同于unix / can / tcp / bluetooth吗?5)还有其他方法可以得到我想要的东西或我自己在逻辑上有严重的缺陷吗?

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

c linux multithreading sockets bluez
1个回答
0
投票
  1. 使用read()打开套接字,并在整个生命周期中都处于非阻塞模式。
  2. 在初始化阶段,调用SOCK_NONBLOCK创建另一个文件描述符。
  3. 而不是在eventfd(0,0)上进行阻止,而是设置并调用readboth]上等待” eventfd文件描述符和套接字(将select超时)。这可能会永远阻止。
  4. 选择返回时:
    • 如果套接字可读,则调用NULL。您正确地认为read可能发出了错误的信号,但是在这种情况下,您会得到select并可以循环返回并再次调用EAGAIN。如果select返回任何其他错误,请通过关闭连接等“处理”它。
    • 如果eventfd文件描述符是可读的,请关闭连接并执行正常关机
  5. 在另一个线程上,您以前试图杀死阻塞thead,现在您可以read到eventfd文件描述符以“中断”选择操作。
© www.soinside.com 2019 - 2024. All rights reserved.