Multithreading 没有显式锁的死锁
我正在测试一个pthread程序 这个程序很简单。主线程创建一个子线程 主线程和子线程都在队列上操作 子线程不断扫描队列,并以无限循环返回最小元素及其位置 主线程也在运行一个循环,每次迭代都会从队列中删除子线程计算的最小元素,并在队列末尾插入一些新元素 最小元素及其位置和队列都声明为全局变量 当队列为空时,主线程结束,它将取消子线程 这一进展有点像广度优先的搜索 队列实现为带有大小计数器的数组。删除操作实现为用最后一个元素替换要删除的元素,并将大小计数器减少一个 这里没有锁。但在运行时,程序会被卡住 更令人惊奇的是,如果我插入一些printf语句来查看状态,它可能会完成 我想知道是什么原因导致这个节目没完没了?Multithreading 没有显式锁的死锁,multithreading,architecture,parallel-processing,pthreads,multicore,Multithreading,Architecture,Parallel Processing,Pthreads,Multicore,我正在测试一个pthread程序 这个程序很简单。主线程创建一个子线程 主线程和子线程都在队列上操作 子线程不断扫描队列,并以无限循环返回最小元素及其位置 主线程也在运行一个循环,每次迭代都会从队列中删除子线程计算的最小元素,并在队列末尾插入一些新元素 最小元素及其位置和队列都声明为全局变量 当队列为空时,主线程结束,它将取消子线程 这一进展有点像广度优先的搜索 队列实现为带有大小计数器的数组。删除操作实现为用最后一个元素替换要删除的元素,并将大小计数器减少一个 这里没有锁。但在运行时,程序会被
struct multiblocks_pthread_args {
volatile int local_e;
volatile int local_v;
volatile int local_pos;
int* Q;
int* val;
volatile int* size;
} para;
volatile int update = 0;
void* child_thread ( void* args ) {
pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
multiblocks_pthread_args* arglist = ( multiblocks_pthread_args* ) args;
bindToCore ( 1 );
int* list = arglist -> Q, * value = arglist -> val;
while ( true ) {
int size, e, v, pos;
do {
size = * ( arglist->size ), e, v = INF, pos = 0;
update = 0;
for ( int i = 0; i < size; i++ ) {
int vi = value[i];
if ( vi < v ) {
pos = i;
v = vi;
}
}
} while ( update );
if ( size > 0 ) e = list[pos];
arglist->local_e = e;
arglist->local_pos = pos;
arglist->local_v = v;
}
return NULL;
}
void main_thread () {
int size;
int* Q = ( int* ) malloc ( sizeof ( int ) * NumNode );
int** hash = ( int** ) malloc ( sizeof ( int* ) * numNode );
NodeColor* color = ( NodeColor* ) malloc ( sizeof ( NodeColor ) * numNode );
// NodeColor is a enum with 3 values: WHITE, GRAY, BLACK
memset ( color, 0, sizeof ( NodeColor ) * numNode );
pthread_t tid;
para.val = ( int* ) malloc ( sizeof ( int ) * NumNode );
para.Q = Q;
para.size = &size;
pthread_create ( &tid, NULL, child_thread, ¶ );
// Only one element is in the queue
size = 0;
para.Q[size] = 0;
para.val[size] = 0;
hash[0] = ¶.val[size]; // hash is used to modify the value of particular element
++size;
color[0] = GRAY;
while ( true ) {
int global_e, global_v = INF, global_pos;
global_e = para.local_e, global_v = para.local_v, global_pos = para.local_pos;
if ( size == 0 ) break;
if ( color[global_e] != BLACK ) {
value[global_e] = global_v, color[global_e] = BLACK;
if ( size > 0 ) {
--size;
para.Q[global_pos] = para.Q[size];
para.val[global_pos] = para.val[size];
hash[para.Q[global_pos]] = & para.val[global_pos];
update = 1;
}
for ( int i = 0; i < MAXDEG; ++i ) {
int ee = ;// new element;
int vv = ;// value of new element;
if ( /* if new element is valid */ ) {
if ( color[ee] == WHITE ) { // WHITE means ee is not in the queue
para.Q[size] = ee;
para.val[size] = vv;
hash[ee] = ¶.val[size];
++size, color[ee] = GRAY;
} else {
*hash[ee] = vv;
}
update = 1;
}
}
}
}
free ( Q );
pthread_cancel ( tid );
printf ( "Computation finishes!!!" );
return ;
}
struct multiblocks\u pthread\u参数{
易失性局部积分;
易失性int-local_-v;
易失性int-local_-pos;
int*Q;
int*val;
可变整数*大小;
}段落;
volatile int update=0;
void*子线程(void*args){
pthread_setcanceltype(pthread_CANCEL_异步,NULL);
多块线程参数*参数列表=(多块线程参数*)参数;
结合剂矿(1);
int*list=arglist->Q,*value=arglist->val;
while(true){
整数大小,e,v,pos;
做{
大小=*(arglist->size),e,v=INF,pos=0;
更新=0;
对于(int i=0;i0)e=列表[pos];
arglist->local_e=e;
arglist->local_pos=pos;
arglist->local_v=v;
}
返回NULL;
}
空主螺纹(){
整数大小;
int*Q=(int*)malloc(sizeof(int)*NumNode);
int**hash=(int**)malloc(sizeof(int*)*numNode);
NodeColor*颜色=(NodeColor*)malloc(sizeof(NodeColor)*numNode);
//NodeColor是一个枚举,有3个值:白色、灰色、黑色
memset(颜色,0,大小(NodeColor)*numNode);
pthread_t tid;
para.val=(int*)malloc(sizeof(int)*NumNode);
第Q段=Q;
para.size=&size;
pthread_create(&tid,NULL,child_thread,¶);
//队列中只有一个元素
尺寸=0;
第Q段[尺寸]=0;
参数值[大小]=0;
哈希[0]=¶.val[size];//哈希用于修改特定元素的值
++大小;
颜色[0]=灰色;
while(true){
int global_e,global_v=INF,global_pos;
全局位置=局部位置,全局位置=局部位置,全局位置=局部位置;
如果(尺寸==0)中断;
如果(颜色[全局颜色]!=黑色){
值[全局值]=全局值,颜色[全局值]=黑色;
如果(大小>0){
--大小;
第Q段[全局位置]=第Q段[大小];
para.val[global_pos]=para.val[size];
hash[para.Q[global_pos]=¶.val[global_pos];
更新=1;
}
对于(int i=0;i
这不是死锁,而是竞争条件
挂起的总体结构是,从索引0处的WHITE
项开始,这个循环将永远持续下去:
size = 1;
while (size != 0) {
if (WHITE) --size;
for (...) {
if (WHITE) ++size;
}
}
这种更改的唯一方式是,您的子线程将设置pos
而不是0
。但您的子线程取决于大于1的大小,使其不是0。这就是你的比赛状态
我的诊断可能不准确。更干净的代码会有很大帮助。像
Q
、e
、v
这样的名称可以为您节省几次击键时间,但很容易让您损失几天时间,如本例所示。您还可以交替使用数字和枚举,这是一种糟糕的做法 共享变量+无锁=>数据竞争,未定义的行为如果没有显式锁,则必须有一些自旋等待。是否有可能存在所有线程无休止循环的边缘情况?噢,printf可能会引入一些同步,这可能会使您的程序“更正确”。没有看到你的代码,我们只能假设你做错了什么。这真的没什么帮助。@hawk当队列确实为空时,子线程可能会运行到一个无止境的循环中。但是在这种情况下,主线程将退出循环取消子线程。我还将这两个线程绑定到不同的内核上。我的代码现在非常复杂。我可以稍后发送一个简单的版本。@KunHuang因为你说“//NodeColor是一个有3个值的枚举:白色、灰色、黑色”,我自然假设白色=0。如果您提供了所有相关的代码就更好了。