试图了解 POSIX 个话题

Trying to understand POSIX Threads

我试图掌握 POSIX 线程的使用,并创建了一个简单的程序,该程序只需将全局变量递增 10。有时它会一直运行良好,其他情况下会出现段错误在 运行dom 点。虽然这种类型的问题似乎是线程的常见问题,但我无法理解为什么在这样一个简单的示例中会发生这种情况。我目前的想法是,由于未加入线程,父级可能在此之前结束,但如果我尝试加入,我会在第一个线程上出现段错误...... Join 语句被保留但被注释掉了。 Join 是否以正确的语法使用?没有执行连接会导致段错误吗?

#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)

一如既往,非常感谢您的帮助。

在考虑你想要什么之前,我发现你的代码有几个问题:

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

主线程在子线程完成互斥量之前销毁它。 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 的地址不会满足您的要求,但这是一个单独的问题,您还没有做到这一点。

你遇到的主要问题是:

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

仔细看,你是在调用philofunct()而不是传递函数指针给它。更糟糕的是,您正在传递 philofunct() 的 return 值,它是一些整数,例如 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);