多线程编程c。互斥量不起作用

时间:2012-08-29 22:59:30

标签: c multithreading pthreads

我有一个用pthreads编写的多线程c程序。我想知道我在做什么是正确的。目前,程序似乎在没有优化时运行。但是当我使用优化时,它会失败。我想弄明白为什么。

我想知道我使用的基本多线程同步是否正确。这是一个简短版本,仅包含相关部分。如果这是多线程的正确方法,请告诉我。

它的工作方式: 每个工人都有许多工作要做。首先启动工作线程。然后他们等到主线程分配给他们的工作。他们完成工作,亲密主线,然后再回去等待。

主线程为N个工作人员分配一份工作,并表示他们要开始工作。然后它等待完成并恢复正常工作。

每个工作线程都有一个名为workerCtx的上下文变量。这将存储worker所需的所有相关信息以及互斥锁和cond变量。

主线程也有一个互斥锁和一个cond变量。

父母也有变量名为threadCompletionCount。在分配工作之前,此变量最初为0。完成每个工作线程后,它将在互斥锁的保护下将此变量递增1并向父线程发出信号。当此变量等于工作人员数时,父线程将知道所有工作人员已完成。

这是workerCtx的简短版本

typedef enum {INITIALIZE = 0 , WAIT = 1, WORK1 = 2, WORK2 =3, DIE = 4} worktype_t;

typedef struct workerCtx_t
{
    int id;

    pthread_mutex_t mutex;
    pthread_cond_t cond;

    pthread_mutex_t * parentMutex;
    pthread_cond_t * parentCond;
    int * parentThreadCompletionCount;

    worktype_t workType;

    //Other application specific variables follow.
}workerCtx_t;

这里mutex和cond引用特定于此线程的本地互斥锁和cond变量。 parentMutex和parentCond是引用父变量的变量。所有线程都指向同一个parentMutex和parentCond。

以下是主线程的工作原理:

void waitForWorkerCompletion()
{
    int status;

    status = pthread_mutex_lock(&mutex);
    while (threadCompletionCount < NUM_WORKERS) 
    {
        status = pthread_cond_wait(&cond, &mutex);
    }
    status = pthread_mutex_unlock(&mutex);

    status = pthread_mutex_lock(&mutex);
        threadCompletionCount = 0;
    status = pthread_mutex_unlock(&mutex);
}

void assignWorkToWorker(worktype_t workType)
{
    for(int i=0; i<NUM_WORKERS; i++)
    {
        pthread_mutex_lock(&(workerCtxs[i]->mutex) );
            workerCtxs[i]->workType = workType;
            pthread_cond_signal(&(workerCtxs[i]->cond) );
        pthread_mutex_unlock(&(workerCtxs[i]->mutex));      
    }
    waitForWorkerCompletion();
}

void setup
{
    for(int i=0; i<NUM_WORKERS; i++)
    {       
        workerCtxs[i]->id = i;
        workerCtxs[i]->workType = WAIT;

        assert( pthread_mutex_init(&(workerCtxs[i]->mutex), NULL) == 0) ;
        assert( pthread_cond_init(&(workerCtxs[i]->cond), NULL) == 0);

        workerCtxs[i]->parentMutex = &mutex;
        workerCtxs[i]->parentCond = &cond;
        workerCtxs[i]->parentThreadCompletionCount = &threadCompletionCount;

        pthread_create (&(workers[i]), NULL, workerMain, (workerCtxs[i]) );

    }
}

int main()
{
    setup()

    For each work (workType_t workType) that comes up
        assignWorkToWorker(workType);
}

以下是每个工人的工作:

void signalCompletion(workerCtx_t * ctx)
{
    pthread_mutex_lock(&ctx->mutex);
        ctx->workType = WAIT;
    pthread_mutex_unlock(&ctx->mutex);

    int rc = pthread_mutex_lock(ctx->parentMutex);
        *(ctx->parentThreadCompletionCount) = *(ctx->parentThreadCompletionCount) + 1;
        pthread_cond_signal(ctx->parentCond);
    rc = pthread_mutex_unlock(ctx->parentMutex);
}

void * workerMain(void * arg)
{
    workerCtx_t * ctx = (workerCtx_t *) arg;

    while(1)
    {
        pthread_mutex_lock(&ctx->mutex);
        while(ctx->workType == WAIT);
        {
            int status = pthread_cond_wait(&ctx->cond, &ctx->mutex);
        }
        pthread_mutex_unlock(&ctx->mutex);

        if(ctx->workType == INITIALIZE)
        {
            init(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == WORK1)
        {
            doWork1(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == WORK2)
        {
            doWork2(ctx);
            signalCompletion(ctx);
        }
        else if(ctx->workType == DIE)
        {
            signalCompletion(ctx);
            break;
        }
    }

    return NULL;
}

我希望我能够轻松地理解并从发布的代码中删除所有面向应用程序的详细信息。此代码只处理多线程部分。现在该程序挂起了。当我使用gdb时,它告诉我它在 waitForWorkerCompletion()方法中等待。

这种多线程模型是否正确?

2 个答案:

答案 0 :(得分:4)

到底是什么,我会把它作为答案。

以下一行看起来非常可疑:

while(ctx->workType == WAIT);

我认为你不想要那里的分号。有了它,你会遇到各种奇怪的竞争条件......这可以解释为什么非优化和优化的构建之间的行为不同。

否则,我认为这段代码没有错。使用工作池是一种奇怪的方式,但在我看来它应该可以工作。

答案 1 :(得分:0)

假设你在某处有以下全局声明,我没有看到任何错误:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int threadCompletionCount = 0;
workerCtx_t workerCtxs[NUM_WORKERS];