C 使用pthreads的多线程代码中的计数器值意外更改
我正在实现一个完整的动态接收器读取器程序:我有许多接收器线程(由用户决定),每个线程连接到一个特定的客户机,然后一个读取线程按时间顺序从接收器的输出队列中读取数据,并在.log文件中打印数据 所以我连接了一个客户端,创建了第一个接收方线程。我无法理解为什么在读取元素后的读取线程中,第二个接收器(尚未创建)的计数器在没有任何此类指令的情况下突然增加1。以下是涉及的代码部分: 接收器线程:C 使用pthreads的多线程代码中的计数器值意外更改,c,multithreading,thread-safety,pthreads,C,Multithreading,Thread Safety,Pthreads,我正在实现一个完整的动态接收器读取器程序:我有许多接收器线程(由用户决定),每个线程连接到一个特定的客户机,然后一个读取线程按时间顺序从接收器的输出队列中读取数据,并在.log文件中打印数据 所以我连接了一个客户端,创建了第一个接收方线程。我无法理解为什么在读取元素后的读取线程中,第二个接收器(尚未创建)的计数器在没有任何此类指令的情况下突然增加1。以下是涉及的代码部分: 接收器线程: printf("Receiver ID: %d, counter: %d\n", rec_arg->re
printf("Receiver ID: %d, counter: %d\n", rec_arg->receiver_ID, *(rec_arg->counter));
rec_arg->joint_queue[*(rec_arg->tail)] = rec_meas;
pthread_mutex_lock(rec_arg->mtx);
*(rec_arg->tail) = (*(rec_arg->tail) + 1) % QUEUE_SIZE;
(*(rec_arg->counter))++;
pthread_mutex_unlock(rec_arg->mtx);
printf("Receiver ID: %d, counter: %d\n", rec_arg->receiver_ID, *(rec_arg->counter));
printf("Receiver: tail: %d, joint_queue: %p\n", *(rec_arg->tail), (void*) rec_arg->joint_queue);
pthread_cond_signal(rec_arg->notEmpty);
阅读线索:
pthread_mutex_lock(read_arg->queue_mtx[i]);
(*(read_arg->counters[i]))--;
printf("Reading Thread: counter[%d]: %d\n", i, *(read_arg->counters[i]));
if( writetofile(filename, &read_meas) == 0)
fprintf(stderr,"Reading Thread: writetofile() failed\n");
*(read_arg->OkRead[i]) = 0;
*(read_arg->OkRead[(i+1) % read_arg->n_joints]) = 1;
pthread_mutex_unlock(read_arg->queue_mtx[i]);
printf("Reading Thread: OkRead[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->OkRead[(i+1) % read_arg->n_joints]));
printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->counters[(i+1) % read_arg->n_joints]));
输出结果显示:
Reading Thread: counter[0]: 0
Reading Thread: OkRead[1]: 1
Reading Thread: counter[1]: 1
Reading Thread: counter[1]: 1
更准确地说,可以创建两个线程,当第一个客户端连接时,它发送数据。接收方线程将数据放入其队列中,读取线程将数据保存在.log文件中,递减计数器[0],将读取权限授予第二个接收方(OkRead[1]=1
),然后,在没有任何关于计数器[1]的说明的情况下,计数器[1]=1
显示一个增量:计数器[1]=1
希望问题能被理解,谢谢您的关注 在读取线程中,您是互斥锁外部的队列计数器。
这意味着另一个线程可以同时修改OkRead[]
和计数器[]
。这是一个很好的例子
读取值后,将调用移动到pthread\u mutex\u unlock()
:
printf("Reading Thread: OkRead[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->OkRead[(i+1) % read_arg->n_joints]));
printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, *(read_arg->counters[(i+1) % read_arg->n_joints]));
pthread_mutex_unlock(read_arg->queue_mtx[i]);
或者在释放互斥锁之前使用存储值的线程局部变量。比如,
...
int joints = (i+1) % read_arg->n_joints;
int okread = *(read_arg->OkRead[(i+1) % read_arg->n_joints]);
int counters = *(read_arg->counters[(i+1) % read_arg->n_joints]);
pthread_mutex_unlock(read_arg->queue_mtx[i]);
printf("Reading Thread: OkRead[%d]: %d\n", joints, okread);
printf("Reading Thread: counter[%d]: %d\n", (i+1) % read_arg->n_joints, counters );
我想出来了。多个线程需要访问的每个参数都必须声明为main()中指针的指针,初始化函数需要其地址 以前,我的代码是这样的: main(): 无效信息初始(整数**信息,整数n元素): 无效信息初始(内部***信息,内部n节点):
*info=malloc(n_接头*sizeof(int*);
如果(*info==NULL)
printf(“队列初始化:malloc失败,错误号:%d,意思是:%s\n”,错误号,strerror(错误号));
int i;
对于(i=0;in .b.),并非所有的竞赛条件都是未定义的行为。在这种错误中,C和C++标准中使用的正式术语是数据竞赛,它总是不确定的行为。这与维基百科称之为“非关键竞赛条件”的情况相反,这是不可预知的(但不是未定义的)。行为。@JonathanWakely感谢您的澄清。数据竞赛是这里实际发生的事情。我已经更新了措辞并更改了链接(这不是更好的权威,但描述正确)。我刚刚编辑了提及数据竞赛的内容,它是UB:)我尝试了两种建议,但它仍然显示了其他线程无法访问的未经检查的价值增量。@nikfio也许,您在其他地方也可以进行类似的无保护访问。在发布的代码中我看不到任何其他问题。张贴一封电子邮件。
int *counter;
info_init(&counter, n_elem);
read_arg->counters = &counter;
*info = malloc(n_joints*sizeof(int*));
if(*info == NULL)
printf("queues_init: malloc failed, errno: %d, meaning: %s\n", errno, strerror(errno));
int i;
for(i=0; i<n_joints; i++) {
info[i] = (int*) malloc(sizeof(int));
*(info[i]) = 0;
}
return;
}
int **counter;
info_init(&counter, n_elem);
read_arg->counters = counter;
*info = malloc(n_joints*sizeof(int*));
if(*info == NULL)
printf("queues_init: malloc failed, errno: %d, meaning: %s\n", errno, strerror(errno));
int i;
for(i=0; i<n_joints; i++) {
(*info)[i] = (int*) malloc(sizeof(int));
*(*info)[i] = 0;
}
return;
}