gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 09:47:52 24 4
gpt4 key购买 nike

我制作了一个线程,可以读取从手机发送的蓝牙消息。
当我意识到我无法安全地杀死那个线程时,我的问题就来了。到目前为止的方法是用户输入,称为 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);
}
}

socket 配置:
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 手动终止进程和 kill -9 PROCESS .

基于此 article我认为最好的方法是引入 if在线程中声明并拥有它 pthread_exit自己陷入了遗忘。如:
if(external_exit){
ret2 = 200;
pthread_exit(&ret2);
}

现在因为 read()是阻塞电话,我永远无法到达 if声明没有外部发生的事情。这个 answer建议使用超时来实现这一点,我遵循了 answer 中的语法设法突破 read()一段时间后。所以我在线程的主while循环之前添加了这个(我认为这应该只定义一次,而不是在每个循环中,虽然不确定因为找不到具体的例子)。

现在我的问题是它会阻塞 read()在第一个循环上,但随后会跳过它,好像什么都没有,只是无限循环。我试图通过重新调用 read() 来“重新启用 accept()listen()bind()没有成功。似乎使用 select()是首先检查是否有要阅读的内容的首选选项,但如手册中所述

“在 Linux 下,select() 可能会将套接字文件描述符报告为“准备就绪”
用于阅读”,而随后的读取 block 。这
例如,当数据到达但经过检查时可能发生
校验和错误并被丢弃”

因此,即使使用它(我不确定它是否可以像在 tcp 套接字上那样在蓝牙套接字上工作),它仍然有可能会卡在 read() 上。没有办法安全地杀死它。

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

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

最佳答案

  • 使用 SOCK_NONBLOCK 打开套接字并在其整个生命周期内保持非阻塞模式。
  • 在初始化阶段,调用eventfd(0,0)创建另一个文件描述符。
  • 而不是阻塞 read ,设置并调用select等待两个 eventfd 文件描述符和套接字(通过 NULL 用于超时)。这可以永远阻塞。
  • 选择返回时:
  • 如果套接字可读,请调用 read .你是对的 select可能会错误地发出信号,但在这种情况下,您会得到 EAGAIN并且可以循环返回并调用select再次。如果 read返回任何其他错误,通过关闭连接等“处理”它。
  • 如果 eventfd 文件描述符可读,关闭连接并执行正常关闭
  • 在另一个线程上,您之前试图杀死阻塞的头,您现在可以 write到 eventfd 文件描述符以“中断”选择操作。
  • 关于c - 如何杀死/结束/取消/加入套接字阻塞线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61110852/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com