该线程属于一个类(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) runStarting 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 runningCancelling threadJoining threadProgram 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吗?
编辑
我不是要求跨平台的解决方案;符合POSIX的解决方案就足够了.
解决方法 我将根据着名的 self-pipe trick建议解决方法,以解锁select(2)
并避开整个凌乱的线程取消业务. 既然你知道你的线程阻塞的socket(7)
的IP地址和端口,只需要sendto(2)
从你的主线程中获得一些众所周知的哨兵包,这表明它是时候打破了循环.
这样您就不必破坏std :: thread抽象,并且可以保持合理的可移植性.
编辑0:
如果您不喜欢变通方法,请将其称为技术:)
总结以上是内存溢出为你收集整理的在recvfrom系统调用期间取消C 11 std :: thread?全部内容,希望文章能够帮你解决在recvfrom系统调用期间取消C 11 std :: thread?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)