- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在使用 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), 0,
(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, (struct sockaddr *) &addr, 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() 发送到线程的 native 句柄的明显方法会导致段错误:
#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, (void *) buf, sizeof(buf), 0,
(struct sockaddr *) &addr, &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, 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, (struct sockaddr *) &addr, 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
在系统调用中阻塞时取消它吗?
编辑
我不是在寻求跨平台解决方案;符合 POSIX 标准的解决方案就足够了。
最佳答案
我将根据众所周知的 self-pipe trick 提出一个解决方法用于解锁 select(2)
并避开整个困惑的线程取消业务。
因为您知道 socket(7)
的 IP 地址和端口你的线程正在阻塞,只是 sendto(2)
从您的主线程向它发送一些众所周知的哨兵数据包,这表明是时候跳出循环了。
这样您就不必破坏 std::thread
抽象并且可以保持合理的可移植性。
如果您不喜欢解决方法,请将其称为技术 :)
关于c++ - 在 recvfrom 系统调用期间取消 C++11 std::thread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12340563/
为了让我的代码几乎完全用 Jquery 编写,我想用 Jquery 重写 AJAX 调用。 这是从网页到 Tomcat servlet 的调用。 我目前情况的类似代码: var http = new
我想使用 JNI 从 Java 调用 C 函数。在 C 函数中,我想创建一个 JVM 并调用一些 Java 对象。当我尝试创建 JVM 时,JNI_CreateJavaVM 返回 -1。 所以,我想知
环顾四周,我发现从 HTML 调用 Javascript 函数的最佳方法是将函数本身放在 HTML 中,而不是外部 Javascript 文件。所以我一直在网上四处寻找,找到了一些简短的教程,我可以根
我有这个组件: import {Component} from 'angular2/core'; import {UserServices} from '../services/UserService
我正在尝试用 C 实现一个简单的 OpenSSL 客户端/服务器模型,并且对 BIO_* 调用的使用感到好奇,与原始 SSL_* 调用相比,它允许一些不错的功能。 我对此比较陌生,所以我可能会完全错误
我正在处理有关异步调用的难题: 一个 JQuery 函数在用户点击时执行,然后调用一个 php 文件来检查用户输入是否与数据库中已有的信息重叠。如果是这样,则应提示用户确认是否要继续或取消,如果他单击
我有以下类(class)。 public Task { public static Task getInstance(String taskName) { return new
嘿,我正在构建一个小游戏,我正在通过制作一个数字 vector 来创建关卡,该数字 vector 通过枚举与 1-4 种颜色相关联。问题是循环(在 Simon::loadChallenge 中)我将颜
我有一个java spring boot api(数据接收器),客户端调用它来保存一些数据。一旦我完成了数据的持久化,我想进行另一个 api 调用(应该处理持久化的数据 - 数据聚合器),它应该自行异
首先,这涉及桌面应用程序而不是 ASP .Net 应用程序。 我已经为我的项目添加了一个 Web 引用,并构建了各种数据对象,例如 PayerInfo、Address 和 CreditCard。但问题
我如何告诉 FAKE 编译 .fs文件使用 fsc ? 解释如何传递参数的奖励积分,如 -a和 -target:dll . 编辑:我应该澄清一下,我正在尝试在没有 MSBuild/xbuild/.sl
我使用下划线模板配置了一个简单的主干模型和 View 。两个单独的 API 使用完全相同的配置。 API 1 按预期工作。 要重现该问题,请注释掉 API 1 的 URL,并取消注释 API 2 的
我不确定什么是更好的做法或更现实的做法。我希望从头开始创建目录系统,但不确定最佳方法是什么。 我想我在需要显示信息时使用对象,例如 info.php?id=100。有这样的代码用于显示 Game.cl
from datetime import timedelta class A: def __abs__(self): return -self class B1(A):
我在操作此生命游戏示例代码中的数组时遇到问题。 情况: “生命游戏”是约翰·康威发明的一种细胞自动化技术。它由一个细胞网格组成,这些细胞可以根据数学规则生存/死亡/繁殖。该网格中的活细胞和死细胞通过
如果我像这样调用 read() 来读取文件: unsigned char buf[512]; memset(buf, 0, sizeof(unsigned char) * 512); int fd;
我用 C 编写了一个简单的服务器,并希望调用它的功能与调用其他 C 守护程序的功能相同(例如使用 ./ftpd start 调用它并使用 ./ftpd stop 关闭该实例)。显然我遇到的问题是我不知
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
在 dos 中,当我粘贴此命令时它会起作用: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" https://google.
我希望能够从 cmd 在我的 Windows 10 计算机上调用 python3。 我已重新安装 Python3.7 以确保选择“添加到路径”选项,但仍无法调用 python3 并使 CMD 启动 P
我是一名优秀的程序员,十分优秀!