试图理解POSIX线程

时间:2015-03-20 23:00:27

标签: c pthreads mutex

我试图掌握POSIX线程的使用并创建了一个简单的程序,它简单地将全局变量递增10个。有时它会一直运行得很好,另外它会在随机点中出现错误。虽然这种类型的问题似乎是线程的常见问题,但我无法理解为什么会在这样一个简单的例子中发生这种情况。我当前的想法可能是由于没有加入线程,父级正在结束,但如果我尝试在第一个线程上加入i seg fault ... Join语句留在但注释掉了。加入是否使用正确的语法?是不是预先形成了导致seg错误的连接?

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>

#define NUMPHILO 5

thread_t threads[NUMPHILO];  //array of threads 
pthread_mutex_t mutex;        // initialize mutex

int x = 5;          //for test
int y = 10;

int philofunct(){
    pthread_mutex_lock (&mutex);
    x = x+y;
    pthread_mutex_unlock (&mutex);
    printf("Philo fucntion x = %d\n",x);
    return x;
}


int main(){

    pthread_mutex_init(&mutex, NULL);

    for(int i = 0; i < NUMPHILO; i++){  
        printf("creating thread[%i]\n",i);
        if( pthread_create(&threads[i], NULL, (void *)philofunct(),(void *) &i) != 0)
            fprintf(stderr, "%s", strerror(errno));
//      pthread_join(threads[i],NULL);  
//      printf("Threads Joined\n");
    }
    pthread_mutex_destroy(&mutex);
    printf("Threads created\n");
}

输出:

creating thread[0]
Philo fucntion x = 15
creating thread[1]
Philo fucntion x = 25
creating thread[2]
Philo fucntion x = 35
creating thread[3]
Philo fucntion x = 45
creating thread[4]
Philo fucntion x = 55
Threads created

下次跑了:

creating thread[0]
Philo fucntion x = 15
creating thread[1]
Philo fucntion x = 25
creating thread[2]
Philo fucntion x = 35
Segmentation fault (core dumped)

与往常一样,非常感谢任何帮助。

3 个答案:

答案 0 :(得分:4)

在考虑您的需求之前,我发现您的代码存在一些问题:

  • 您不能像这样投射函数指针并期望得到有意义的结果。相反,为函数提供正确的签名,并在函数的边缘转换参数/返回值。但是你通常不需要使用返回值。
  • 您正在访问由互斥锁锁定的部分之外的变量x
  • 您正在销毁互斥锁​​,而不等待所有使用它的线程退出。你需要第二个循环来pthread_join全部。或者,您可以pthread_exit主线程而不是让main终止(并且永远不会破坏互斥,这不是泄漏,因为那里只有其中一个,其生命周期以生命周期结束该程序),但杀死主线程有时会使有趣的内核&#34;错误&#34;发生。

答案 1 :(得分:4)

你遇到的主要问题是:

    if( pthread_create(&threads[i], NULL, (void *)philofunct(),(void *) &i) != 0)

仔细看,您正在调用philofunct()而不是将函数指针传递给它。更糟糕的是,您将philofunct()的返回值作为15的函数指针传递,这是pthread_create()之类的整数。当然,当线程尝试从15等地址执行代码时,线程将会被segv。

正确定义philofunct()之后:

void *philofunct(void *arg)

然后,您可以在没有演员阵容的情况下致电pthread_create()

    if( pthread_create(&threads[i], NULL, philofunct,(void *) &i) != 0)

另外,如果你想加入你的线程,你应该在它们全部运行后加入你的线程。如果在创建循环中加入线程,则在创建下一个线程之前,您将等待每个线程完成。所以你会这样写:

for (i=0;i<NUMPHILO; i++) {
    pthread_create(&threads[i], ...);
    // Other stuff...
}
for (i=0;i<NUMPHILO; i++)
    pthread_join(threads[i], NULL);

答案 2 :(得分:1)

主线程在子线程完成之前销毁互斥锁​​。 pthread_join将解决问题,但pthread_join需要在创建所有线程后的单独循环中。

for(int i = 0; i < NUMPHILO; i++) 
   pthread_join(threads[i],NULL); 

philofunct的功能签名是错误的。一般来说,如果你需要演员,你做错了。 (是的,在某些情况下,演员阵容是必要且有用的。这不是其中之一。)正确的签名是

void *philofunct( void *arg );

正确调用pthread_create

if( pthread_create(&threads[i], NULL, philofunct, NULL) != 0)

请注意,传递i的地址不会达到您想要的效果,但这是一个单独的问题,而您还没有达到这一点。