以下代码是一个简单的线程游戏,它在线程之间切换,导致计时器减少。
它适用于3个线程,原因和4个线程的Abort(核心转储),并导致5个或更多线程的seg错误。
任何人都知道为什么会发生这种情况?
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
int volatile num_of_threads;
int volatile time_per_round;
int volatile time_left;
int volatile turn_id;
int volatile thread_running;
int volatile can_check;
void * player (void * id_in){
int id= (int)id_in;
while(1){
if(can_check){
if (time_left<=0){
break;
}
can_check=0;
if(thread_running){
if(turn_id==id-1){
turn_id=random()%num_of_threads;
time_left--;
}
}
can_check=1;
}
}
pthread_exit(NULL);
}
int main(int argc, char *args[]){
int i;
int buffer;
pthread_t * threads =(pthread_t *)malloc(num_of_threads*sizeof(pthread_t));
thread_running=0;
num_of_threads=atoi(args[1]);
can_check=0;
time_per_round = atoi(args[2]);
time_left=time_per_round;
srandom(time(NULL));
//Create Threads
for (i=0;i<num_of_threads;i++){
do{
buffer=pthread_create(&threads[i],NULL,player,(void *)(i+1));
}while(buffer == EAGAIN);
}
can_check=1;
time_left=time_per_round;
turn_id=random()%num_of_threads;
thread_running=1;
for (i=0;i<num_of_threads;i++){
assert(!pthread_join(threads[i], NULL));
}
return 0;
}
答案 0 :(得分:2)
请参阅下文,了解为什么不应该依赖volatile
pthreads。但是,您的特定问题可能是因为您在之前基于num_of_threads
变量对您的pthread数组进行了malloc实际设置num_of_thread
来自{ {1}}:
argv[]
因此,非常很有可能在pthread_t *threads = (pthread_t *)malloc (num_of_threads * sizeof (pthread_t));
thread_running = 0;
num_of_threads = atoi (args[1]);
数组的末尾之外写作。启动时threads
变量可能为零,这意味着您没有分配您认为自己的内容。 在提取参数之后将分配移动到,并且应该修复它。
现在,为了您的观赏乐趣:-),我对num_of_threads
的不安全使用的原始咆哮,我仍然支持。
不依靠volatile
来保护您的共享变量。正确的方法是使用volatile
来电。
特别需要注意的是,请检查此代码段:
pthread_mutex_blab_blah_blah
if (can_check) {
if (time_left <= 0) {
break;
}
// URK!!
can_check=0;
是当前线程可能被切换出来并且另一次运行的点,导致两个线程可能正在运行代码的关键部分。
我的建议是完全忘记URK!!
并使用互斥锁保护所有共享变量,例如(来自内存):
can_check
然后放在文件级:
void *player (void * id_in) {
int id = (int)id_in;
while (1) {
pthread_mutex_lock (&mutex);
if (time_left <= 0) {
pthread_mutex_unlock (&mutex);
break;
}
if (thread_running) {
if (turn_id == id-1) {
turn_id = random() % num_of_threads;
time_left--;
}
}
pthread_mutex_unlock (&mutex);
}
pthread_exit(NULL);
}
并且,在main中,在开始任何其他线程之前:
pthread_mutexattr_t mutexattr; // prob. not needed at file level.
pthread_mutex_t mutex;
哦,是的,虽然我没有这样做,但您还应该检查所有这些互斥锁调用的返回码。我不打算补充说,因为它会用不必要的细节堵塞答案,但这是很好的做法。