3

我有一个用 pthreads 编写的多线程 c 程序。我想知道我所做的是否正确。目前,该程序似乎在没有优化时运行。但是当我使用优化时,它失败了。我试图找出原因。

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

它的工作方式:每个工人都有许多工作要做。工作线程首先启动。然后他们等到主线程分配给他们一个工作。他们完成了工作,关闭了主线程并再次返回等待。

主线程将作业分配给 N 个工作人员并通知他们开始。然后它等待它们完成并恢复正常工作。

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

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

父级也有一个名为 threadCompletionCount 的变量。在分配工作之前,该变量最初为 0。一旦每个工作线程完成,它将在互斥锁的保护下将该变量加一并向父线程发出信号。当这个变量等于worker的数量时,父线程就会知道所有的worker都已经完成了。

这是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 指的是特定于该线程的本地 mutex 和 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()方法中等待。

这个多线程模型正确吗?

4

2 回答 2

4

什么鬼,我会回答这个问题。

以下行看起来非常可疑:

while(ctx->workType == WAIT);

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

否则,我认为这段代码没有任何问题。使用工作池的方式有点奇怪,但在我看来它应该可以工作。

于 2012-08-30T00:09:58.557 回答
0

假设您在某处有以下全局声明,我看不出有什么问题:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int threadCompletionCount = 0;
workerCtx_t workerCtxs[NUM_WORKERS];
于 2012-08-29T23:44:28.327 回答