pthread_create 上的分段错误

Posted

技术标签:

【中文标题】pthread_create 上的分段错误【英文标题】:Segmentation Fault on pthread_create 【发布时间】:2018-03-28 01:53:12 【问题描述】:

我对以下 C 代码有疑问。代码本身应该创建 5 个线程来模拟餐饮哲学家问题,其中线程正在访问共享数据。代码如下:

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

//creation of the mutex lock, condition variables, and state
pthread_mutex_t mutex;
pthread_cond_t cond_var[5];
enumTHINKING, HUNGRY, EATINGstate[5];

//test if possible to get forks
void test(int pNumber)

    //start eating if the adjacent philosophers aren't eating
    if((state[(pNumber + 1) % 5] != EATING) && (state[(pNumber + 4) % 5] != EATING))
        state[pNumber] = EATING;

        //signal self if test() called by another thread
        pthread_cond_signal(&cond_var[pNumber]);
    


//used to make the philosopher's forks unavailable
void pickup_forks(int pNumber)

    //get lock
    pthread_mutex_lock(&mutex);

    //set state to hungry
    state[pNumber] = HUNGRY;
    printf("Philosopher %d is HUNGRY\n", pNumber);

    //attempt to begin eating. if unable to, will wait
    test(pNumber);
    while(state[pNumber] != EATING)
        pthread_cond_wait(&cond_var[pNumber], &mutex);
        //switched the order of the arguments
    

    //release lock
    pthread_mutex_unlock(&mutex);


//allow neighbors to use philosopher's forks
void release_forks(int pNumber)

    //get lock
    pthread_mutex_lock(&mutex);

    //set own state to thinking
    state[pNumber] = THINKING;

    //tell adjacent philosophers to try to eat
    test(((pNumber + 1) % 5)); 
    test(((pNumber + 4) % 5));

    //release lock
    pthread_mutex_unlock(&mutex);


//used by the thread to run the philosophers
void *runPhilosopher(void *x)

    //which philosopher it is
    int pNumber = *((int*) x);

    //initially thinking
    state[pNumber] = THINKING;
    printf("Philosopher %d is THINKING\n", pNumber);

    //"think" for a random amount of time between 1-3 seconds
    int sleepTime = rand() % 3 + 1;
    sleep(sleepTime);

    //each philosopher eats a total of 5 times
    int i = 0;
    for(i = 0; i < 5; i++)

        //get the forks and begin eating
        pickup_forks(pNumber);

        //eating time
        sleep(2);

        //put down forks and resume thinking
        release_forks(pNumber);
        sleepTime = rand() % 3 + 1;
        sleep(sleepTime);
    

    printf("Philosopher %d has finished eating\n", pNumber);


int main(int argc, char *argv[])


    pthread_mutex_init(&mutex, NULL);

    int i = 0;
    for(i = 0; i < 5; i++)
        pthread_cond_init(&cond_var[i], NULL);
    


    pthread_t tid[5];    //thread id
    pthread_attr_t attr;     //set of thread attributes

    pthread_create(&tid[0], NULL, runPhilosopher, (void *) 0);
    pthread_create(&tid[1], NULL, runPhilosopher, (void *) 1);
    pthread_create(&tid[2], NULL, runPhilosopher, (void *) 2);
    pthread_create(&tid[3], NULL, runPhilosopher, (void *) 3);
    pthread_create(&tid[4], NULL, runPhilosopher, (void *) 4);

    //wait for threads to finish
    for(i = 0; i < 5; i++)
        pthread_join(tid[i], NULL);
    

    return 0;

我在使用 gedit 的 Linux 虚拟机上。该程序编译得很好,但是在尝试运行它时,我得到一个“分段错误”错误,这是来自尝试的线程创建,根据 gdb。我发现这里的相关问题都没有适用于我的程序。

我尝试过的事情:

注释掉绝大多数代码并尝试创建一个简单地运行 runPhilosopher 的线程,该线程已被剥离为仅一个 printf 语句。这导致代码似乎没有创建线程,因为没有输出。 用 &attr 替换线程创建中的 NULL。这将错误更改为已中止,但没有执行任何其他操作。 对所有这些都使用一个线程 ID,就像我在之前的程序中所做的那样。这没什么区别。 其他一些我不记得的零碎事情

是否有人看到了我忽略的简单解决方案,或者我的程序中是否存在严重缺陷?我无法理解问题可能是什么,但我完全承认我对 C 语言并不精通。任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

你的问题在这里:

int pNumber = *((int*) x);

在调用pthread_create() 时将整数转换为指针,但随后将其转换为线程函数中的指针并继续取消引用。

相反,试试

    int pNumber = (int) x;

请注意,这可能会导致编译器警告sizeof(int) != sizeof(void*)。您可能想先投射到uintptr_t

或者,您可以将int 存储在局部变量中,并将其地址传递给pthread_create。只需确保在包含函数返回之前所有线程都已停止。

或者,您可以malloc 将此int 作为成员的结构,并将指针传递给它。

【讨论】:

不是唯一的问题,但这个修复让我找到了解决问题的正确方向,谢谢!

以上是关于pthread_create 上的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 pthread_create 时出现“分段错误(核心转储)”

使用pthread_create时的“分段错误(核心转储)”

glCreateShader 上的 GLUT 分段错误

Linux上的AVX分段错误[关闭]

join() 上的 Boost 线程分段错误

向量分配上的c ++分段错误