我正在实现一个完整的动态Receivers-Reader程序:我有许多Receiver Threads(由用户决定),每个都连接到一个特定的客户端,然后一个读取线程按时间顺序从Receivers的输出队列中读取并在.log文件中打印数据。
所以我连接一个客户端,创建了第一个Receiver Thread。我无法理解为什么在阅读元素之后突然在阅读线程中,第二个接收器(尚未创建)的计数器在没有任何指令的情况下增加1。以下是涉及的代码部分:
接收线程:
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}}显示增量:counter[1]
。
希望能够理解这个问题,谢谢你的关注。
答案 0 :(得分:1)
在阅读线程中,您是外部的队列计数器互斥锁。
这意味着另一个线程可以在此期间修改OkRead[]
和counters[]
。这是data race,undefined behaviour。
在读取值后,将呼叫移至pthread_mutex_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 );
答案 1 :(得分:1)
我明白了。每个参数,多个线程需要访问,必须在main()中声明为指针,初始化函数需要他的地址。
以前,我的代码就像:
主要():
int *counter;
info_init(&counter, n_elem);
read_arg->counters = &counter;
void info_init(int ** info,int n_elem):
*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;
void info_init(int *** info,int n_joints):
*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;
}
现在程序正常运行,感谢@ l3x的帮助。