- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个用 C 语言编写的无锁队列,其形式为链表,其中包含来自多个线程的请求,这些线程发布到单个线程并在其中处理。经过几个小时的压力,我最终让最后一个请求的下一个指针指向它自己,这创建了一个无限循环并锁定了处理线程。
应用程序在 Linux 和 Windows 上运行(并失败)。我在 Windows 上调试,我的 COMPARE_EXCHANGE_PTR
映射到 InterlockedCompareExchangePointer .
这是将请求推送到列表头部的代码,并从多个线程调用:
void push_request(struct request * volatile * root, struct request * request)
{
assert(request);
do {
request->next = *root;
} while(COMPARE_EXCHANGE_PTR(root, request, request->next) != request->next);
}
这是从列表末尾获取请求的代码,并且仅由处理它们的单个线程调用:
struct request * pop_request(struct request * volatile * root)
{
struct request * volatile * p;
struct request * request;
do {
p = root;
while(*p && (*p)->next) p = &(*p)->next; // <- loops here
request = *p;
} while(COMPARE_EXCHANGE_PTR(p, NULL, request) != request);
assert(request->next == NULL);
return request;
}
请注意,我没有使用尾指针,因为我想避免必须在 push_request
中处理尾指针的复杂情况。但是我怀疑问题可能出在我找到列表末尾的方式上。
有几个地方可以将请求推送到队列中,但它们大体上看起来都是这样的:
// device->requests is defined as struct request * volatile requests;
struct request * request = malloc(sizeof(struct request));
if(request) {
// fill out request fields
push_request(&device->requests, request);
sem_post(device->request_sem);
}
处理请求的代码做的不止这些,但本质上是在循环中进行的:
if(sem_wait_timeout(device->request_sem, timeout) == sem_success) {
struct request * request = pop_request(&device->requests);
// handle request
free(request);
}
我还刚刚添加了一个功能,在每次操作前后检查列表是否重复,但我担心这个检查会改变时间,这样我就永远不会遇到失败的地方。 (我在写这篇文章时正在等待它崩溃。)
当我中断挂起的程序时,处理程序线程在标记位置的 pop_request
中循环。我有一个包含一个或多个请求的有效列表,最后一个的下一个指针指向它自己。请求队列通常很短,我从未见过超过 10 个,而且只有 1 和 3 两次我可以在调试器中查看此故障。
我尽可能多地考虑了这一点,并得出结论,除非我两次推送相同的请求,否则我永远不会在我的列表中出现循环。我很确定这永远不会发生。我也很确定(虽然不完全)它不是 ABA problem .
我知道我可能会同时弹出多个请求,但我相信这在这里无关紧要,而且我从未见过这种情况发生。 (我也会解决这个问题)
我对如何破坏我的功能进行了长期而艰苦的思考,但我没有找到以循环结束的方法。
所以问题是:有人能看出破解方法吗?有人能证明这不能吗?
最终我会解决这个问题(也许通过使用尾指针或其他一些解决方案 - 锁定将是一个问题,因为发布的线程不应该被锁定,虽然我手头有一个 RW 锁)但我想确保更改列表确实解决了我的问题(而不是因为时间不同而降低了它的可能性)。
最佳答案
这很微妙,但确实存在竞争条件。
从一个包含一个元素的列表开始,req1
。所以我们有:
device->requests == req1;
req1->next == NULL;
现在,我们推送一个新元素 req2
,同时尝试弹出队列。 req2
的推送首先开始。 while 循环体运行,所以我们现在有:
device->requests == req1;
req1->next == NULL;
req2->next == req1;
然后 COMPARE_EXCHANGE_PTR
运行,所以我们有:
device->requests == req2;
req1->next == NULL;
req2->next == req1;
...COMPARE_EXCHANGE_PTR()
返回 req1
。现在,此时,在 while
条件下进行比较之前,推送被中断,弹出开始运行。
弹出正确运行到完成,弹出 req1
- 这意味着我们有:
device->requests == req2;
req2->next == NULL;
推送重新开始。它现在获取 request->next
来进行比较 - 它获取 req2->next
的 new 值,即 空
。它将 req1
与 NULL
进行比较,比较成功,while 循环再次运行,现在我们有:
device->requests == req2;
req2->next == req2;
这次测试失败,while 循环退出,你有你的循环。
这应该可以解决:
void push_request(struct request * volatile * root, struct request * request)
{
struct request *oldroot;
assert(request);
do {
request->next = oldroot = *root;
} while(COMPARE_EXCHANGE_PTR(root, request, oldroot) != oldroot);
}
关于c - 无锁队列实现最终在压力下有一个循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2715497/
已关闭。此问题旨在寻求有关书籍、工具、软件库等的建议。不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以
我在 tomcat 服务器上部署了一个 Web 应用程序。我通过 POST 方法上传文件,然后上传文件被转码为另一种类型(例如 3gp 到 flv)。我如何测试,有多少并发上传和转码我的 Web 应用
我想知道是否有任何方法可以获取单击时的压力级别(用户单击鼠标键/按钮时产生的压力)。有资源或链接吗? 抱歉我的英语不好,希望我的问题很清楚,希望不仅仅是乌托邦! 最佳答案 我意识到我正在用一些当时不相
我写信是为了问一个关于 WCF 性能的问题。 1。背景 我们有一个在 .NET 3.5 上运行的客户端-服务器系统。服务器是 C# 服务,客户端是 silverlight 应用。 我写了一个压力测
我想编写一份包含 NMS 排序的报告。我想在报告中包含代码,但不包含运行压力。 我试过 message=FALSE, warning=FALSE, results='hide' 但它仍然包含在报告中。
我今天第一次尝试使用 cassandra-stress 工具。尽管我能够运行该工具,但输出中会显示很多“无法通过 JMX 连接;未收集这些统计信息”消息 命令 cassandra-stress use
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我希望通过一遍又一遍地不断访问网址列表来模拟网络服务器上的重负载! 最初,我计划使用 wget/curl 编写一个简单的脚本,但由于该站点使用大量 ajax 请求来完成大部分繁重的工作,因此这不是一个
我最近创建了一个回合制游戏服务器,可以接受数以万计的同时客户端连接(长话短说 - Linux 上的 epoll)。通信基于简单、自定义、基于线路的协议(protocol)。该服务器允许客户端连接、寻找
Stress-ng:我们可以使用stress-ng测试RAM吗?用于在 MIPS 32 设备上测试 RAM 的命令是什么? 最佳答案 在stress-ng中有许多基于内存的压力源: stress-ng
我正在 iPhone 上测试我的简单 OpenGL ES 实现(2D 游戏),并且在使用分析器时我注意到渲染利用率很高。这些是事实: 我以 60 fps 的速度仅显示一个预加载的大型纹理(512x51
我正在 canvas 上编写应该支持平板电脑和触摸压力的网络应用程序。不过,如果我没记错的话,我相信只有IE10支持这些指针事件。我想知道 chrome 和 firefox 是否会很快支持它? 最佳答
Stress-ng:如何使用 execv 在 C 或 Cpp 中编写应用程序来调用 stress-ng 命令以在 MIPS 中进行 CPU 和内存测试,并在成功或失败时返回其状态?给定一个可执行的 s
我是一名优秀的程序员,十分优秀!