在recvfrom系统调用期间取消C 11 std :: thread?

在recvfrom系统调用期间取消C 11 std :: thread?,第1张

概述我正在使用C 11 std :: thread.它的主循环包括一个阻塞的recvfrom()调用,它监听到达DATAGRAM套接字的UDP数据包,以及一些复杂的代码,用于解析消息并在进程中处理大量的STL容器. 该线程属于一个类(helloexchange),由构造函数启动,应该在析构函数中取消. 出于显而易见的原因,我不想强​​行终止线程,因为这可能会破坏数据结构,这些数据结构部分位于类之外. 我正在使用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) 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?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1240580.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存