我正在使用C 11 std :: thread.它的主循环包括一个阻塞的recvfrom()调用,它监听到达DATAGRAM套接字的UDP数据包,以及一些复杂的代码,用于解析消息并在进程中处理大量的STL容器.
该线程属于一个类(helloexchange),由构造函数启动,应该在析构函数中取消.
出于显而易见的原因,我不想强行终止线程,因为这可能会破坏数据结构,这些数据结构部分位于类之外.
当使用pthread而不是std :: thread时,有pthread_cancel方法,它与pthread_setcancelstate一起提供了我需要的所有功能:它只会在某些系统调用阻塞时取消该线程,并且取消可以完全取消对某些部分禁用.一旦再次启用取消,则执行取消.
这是工作pthread代码的完整示例:
#include <arpa/inet.h> #include <unistd.h> #include <iostream> #include <sys/socket.h> #include <sys/types.h> #include <cstdio> #include <pthread.h> #include <net/if.h> #include <ifaddrs.h> int sock; void *tfun(void *arg) { std::cout << "Thread running" << std::endl; while(true) { char buf[256]; struct sockaddr_in addr; addr.sin_family = AF_INET; socklen_t addrlen = sizeof(addr); //allow cancelling the thread pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); //perform the blocking recvfrom syscall int size = recvfrom(sock,(void *) buf,sizeof(buf),(struct sockaddr *) &addr,&addrlen); //disallow cancelling the thread pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL); if(size < 0) { perror("Could not receive packet"); return NULL; } else { //process the packet in the most complex ways //you could imagine. std::cout << "Packet received: " << size << " bytes"; std::cout << std::endl; } } return NULL; } int main() { //open datagram socket sock = socket(AF_INET,SOCK_DGRAM,0); if(sock < 0) { perror("Could not open socket"); return 1; } //bind socket to port struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1337); addr.sin_addr.s_addr = 0; if(bind(sock,sizeof(addr)) < 0) { perror("Could not bind datagram socket"); return 2; } //create the listener thread pthread_t t; if(pthread_create(&t,NULL,tfun,NULL) != 0) { perror("Could not thread"); return 3; }; //wait std::cin.get(); //cancel the listener thread. pthread_cancel does not block. std::cout << "Cancelling thread" << std::endl; if(pthread_cancel(t) != 0) { perror("Could not cancel thread"); } //join (blocks until the thread has actually cancelled). std::cout << "Joining thread" << std::endl; if(pthread_join(t,NULL) != 0) { perror("Could not join thread"); } else { std::cout << "Join successful" << std::endl; } //close socket if(close(sock) != 0) { perror("Could not close socket"); }; }
但是,std :: thread不支持cancel,std :: this_thread也不支持setcancelstate(你会找到一个引用here).但它确实支持native_handle,它返回内部使用的pthread_t id.
然而,将pthread_cancel()发送到线程的本机句柄的明显方法会导致分段错误:
#include <iostream> #include <thread> #include <cstdio> #include <arpa/inet.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <pthread.h> #include <net/if.h> #include <ifaddrs.h> int sock; void tfun() { std::cout << "Thread running" << std::endl; while(true) { char buf[256]; struct sockaddr_in addr; addr.sin_family = AF_INET; socklen_t addrlen = sizeof(addr); //perform the blocking recvfrom syscall int size = recvfrom(sock,&addrlen); if(size < 0) { perror("Could not receive packet"); return; } else { //process the packet in the most complex ways //you could imagine. std::cout << "Packet received: " << size << " bytes"; std::cout << std::endl; } } return; } int main() { //open datagram socket sock = socket(AF_INET,sizeof(addr)) < 0) { perror("Could not bind datagram socket"); return 2; } //the listener thread std::thread *t = new std::thread(&tfun); //wait std::cin.get(); //cancel the listener thread. pthread_cancel does not block. std::cout << "Cancelling thread" << std::endl; if(pthread_cancel(t->native_handle()) != 0) { perror("Could not cancel thread"); } //join (blocks until the thread has actually cancelled). std::cout << "Joining thread" << std::endl; t->join(); delete t; //close socket if(close(sock) != 0) { perror("Could not close socket"); }; }
结果是:
(gdb) run Starting program: /tmp/test/test-dbg warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". [New Thread 0x7ffff6550700 (LWP 11329)] Thread running Cancelling thread Joining thread Program received signal SIGSEGV,Segmentation fault. [Switching to Thread 0x7ffff6550700 (LWP 11329)] 0x00007ffff6e67b45 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/libstdc++.so.6
有什么方法可以在系统调用中阻止std :: thread吗?
编辑