- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
递归调用 pthread_create() 时出现数据争用。我不知道递归是否导致问题,但竞争似乎从未发生在第一次迭代中,大部分发生在第二次迭代中,很少发生在第三次迭代中。
使用 libgc 时,会出现内存损坏的症状,例如 segmentation fault,这与数据竞争是一致的。
以下程序是说明问题的最小示例。我没有在示例中使用 libgc,因为只有数据竞争是这个问题的主题。
使用 Helgrind 工具运行 Valgrind 时可以看到数据争用。报告的问题略有不同,有时根本没有问题。
我正在运行 Linux Mint 17.2。 gcc版本为(Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4。
以下示例“main.c”重现了该问题。它遍历链表,在单独的线程中打印每个元素值:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
typedef struct List {
int head ;
struct List* tail ;
} List ;
// create a list element with an integer head and a tail
List* new_list( int head, List* tail ) {
List* l = (List*)malloc( sizeof( List ) ) ;
l->head = head ;
l->tail = tail ;
return l ;
}
// create a thread and start it
void call( void* (*start_routine)( void* arg ), void* arg ) {
pthread_t* thread = (pthread_t*)malloc( sizeof( pthread_t ) ) ;
if ( pthread_create( thread, NULL, start_routine, arg ) ) {
exit( -1 ) ;
}
pthread_detach( *thread ) ;
return ;
}
void print_list( List* l ) ;
// start routine for thread
void* print_list_start_routine( void* arg ) {
// verify that the list is not empty ( = NULL )
// print its head
// print the rest of it in a new thread
if ( arg ) {
List* l = (List*)arg ;
printf( "%d\n", l->head ) ;
print_list( l->tail ) ;
}
return NULL ;
}
// print elements of a list with one thread for each element printed
// threads are created recursively
void print_list( List* l ) {
call( print_list_start_routine, (void*)l ) ;
}
int main( int argc, const char* argv[] ) {
List* l = new_list( 1, new_list( 2, new_list( 3, NULL ) ) ) ;
print_list( l ) ;
// wait for all threads to finnish
pthread_exit( NULL ) ;
return 0 ;
}
这是“makefile”:
CC=gcc
a.out: main.o
$(CC) -pthread main.o
main.o: main.c
$(CC) -c -g -O0 -std=gnu99 -Wall main.c
clean:
rm *.o a.out
这是 Helgrind 最常见的输出。请注意只有一个数字 1、2 和 3 的行是程序的输出而不是 Helgrind:
$ valgrind --tool=helgrind ./a.out
==13438== Helgrind, a thread error detector
==13438== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==13438== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==13438== Command: ./a.out
==13438==
1
2
==13438== ---Thread-Announcement------------------------------------------
==13438==
==13438== Thread #3 was created
==13438== at 0x515543E: clone (clone.S:74)
==13438== by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==13438== by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==13438== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4007EB: call (main.c:25)
==13438== by 0x400871: print_list (main.c:58)
==13438== by 0x40084D: print_list_start_routine (main.c:48)
==13438== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4E45181: start_thread (pthread_create.c:312)
==13438== by 0x515547C: clone (clone.S:111)
==13438==
==13438== ---Thread-Announcement------------------------------------------
==13438==
==13438== Thread #2 was created
==13438== at 0x515543E: clone (clone.S:74)
==13438== by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==13438== by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==13438== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4007EB: call (main.c:25)
==13438== by 0x400871: print_list (main.c:58)
==13438== by 0x4008BB: main (main.c:66)
==13438==
==13438== ----------------------------------------------------------------
==13438==
==13438== Possible data race during write of size 1 at 0x602065F by thread #3
==13438== Locks held: none
==13438== at 0x4C368F5: mempcpy (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4012CD6: _dl_allocate_tls_init (dl-tls.c:436)
==13438== by 0x4E45715: pthread_create@@GLIBC_2.2.5 (allocatestack.c:252)
==13438== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4007EB: call (main.c:25)
==13438== by 0x400871: print_list (main.c:58)
==13438== by 0x40084D: print_list_start_routine (main.c:48)
==13438== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==13438== by 0x4E45181: start_thread (pthread_create.c:312)
==13438== by 0x515547C: clone (clone.S:111)
==13438==
==13438== This conflicts with a previous read of size 1 by thread #2
==13438== Locks held: none
==13438== at 0x51C10B1: res_thread_freeres (in /lib/x86_64-linux-gnu/libc-2.19.so)
==13438== by 0x51C1061: __libc_thread_freeres (in /lib/x86_64-linux-gnu/libc-2.19.so)
==13438== by 0x4E45199: start_thread (pthread_create.c:329)
==13438== by 0x515547C: clone (clone.S:111)
==13438==
3
==13438==
==13438== For counts of detected and suppressed errors, rerun with: -v
==13438== Use --history-level=approx or =none to gain increased speed, at
==13438== the cost of reduced accuracy of conflicting-access information
==13438== ERROR SUMMARY: 8 errors from 1 contexts (suppressed: 56 from 48)
正如 Pooja Nilangekar 所提到的,将 pthread_detach() 替换为 pthread_join() 可以消除竞争。但是,分离线程是一项要求,因此目标是干净地分离线程。换句话说,在消除竞争的同时保留 pthread_detach()。
线程之间似乎有一些无意的共享。意外共享可能与此处讨论的内容有关:http://www.domaigne.com/blog/computing/joinable-and-detached-threads/特别是示例中的错误。
我还是不明白到底发生了什么。
最佳答案
helgrind 的输出与您的来源不匹配。根据 helgrind 的说法,第 25 行有一个 pthread_create
调用,但我看到的只是 exit(-1)
。我假设您忘记在源代码的开头添加一行。
也就是说,我根本无法重现 helgrind 的输出。我在 while 循环中运行了你的程序,希望得到同样的错误,但是 nada。这就是比赛的坏处 - 你永远不知道比赛何时发生,而且很难追踪。
还有一件事:每当要释放解析器状态信息 (DNS) 时,都会调用 res_thread_freeres
。实际上,它甚至没有被检查就被调用了。 _dl_allocate_tls_init
用于线程本地存储 (TLS),并确保在您的函数控制线程之前分配/存储某些资源和元数据(自定义堆栈、清理信息等)。
这表明在创建新线程和杀死旧线程之间存在竞争。由于您分离了线程,因此父线程可能会在子线程完成之前死亡。在这种情况下,同步线程的退出(Pooja Nilangekar 指出这可以通过加入它们来完成)可能会解决问题,因为 pthread_join
会停止直到线程完成,从而同步子/父释放.
如果您仍然想要并行处理,您可以做的是自己处理内存。请参阅此处的 pthread_attr_setstack
。由于我无法重现错误,所以我不确定这是否真的有效。此外,这种方法要求您知道您将拥有的线程数量。如果您尝试重新分配线程当前使用的内存,那么您就是在玩火。
关于c - 为什么这个递归的 pthread_create 调用会导致数据竞争?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32560834/
假设我正在使用 APC,其中过程和调用代码都使用 SetLastError 和 GetLastError。这会导致 GetLastError 产生不可预测的值。有什么办法可以解决这个问题吗? VOID
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 7年前关闭。 Improve t
任何人都可以,请告诉我,如何在不进行JavaScript轮询/ setInterval的情况下,在完整日历上填充/显示在服务器端动态更新的数据。 grails中提供了Atmosphere插件,但是文档
我正在尝试调整我的代码,从仅在前台使用 WCSessionDelegate 回调到在后台通过 handleBackgroundTasks: 接受 WKWatchConnectivityRefreshB
我正在构建批处理系统。 单位 的批处理数量从 20 到 1000 不等。每个 Unit 本质上都是模型的层次结构(一个主模型和许多子模型)。我的任务涉及将每个模型层次结构作为单个事务保存到数据库中(每
我拍了一张图片并将其切成三 block ,然后将它们向右浮动,让文字围绕它们流动。 HTML 看起来像这样: 在我添加侧边栏并将其 float 到图像的右上方之前,它工作正常,就像这样... T
我正在考虑嵌入式 Linux 项目(还没有硬件)中即将出现的情况,其中两个外部芯片需要共享一条物理 IRQ 线。这条线在硬件中能够实现边沿触发,但不能实现电平触发中断。 查看 Linux 中的共享 i
我观察到,当 linux futexes 发生争用时,系统会在自旋锁上花费大量时间。我注意到即使不直接使用 futex 也是一个问题,但在调用 malloc/free、rand、glib 互斥调用和其
我终于能够获得一些工具提示,最终可以使用以下代码: Hover over me 然后 $('[rel=tooltip]').tooltip(); 我遇到的问题是它使用 jQueryUI 工
我是一名优秀的程序员,十分优秀!