pthread_join()的版本不阻止main():POSIX

时间:2014-07-01 19:02:38

标签: c multithreading posix

我正在尝试编写一个在调用main()时不会阻止pthread_join()的代码: 即基本上试图实现我之前提到的问题:

https://stackoverflow.com/questions/24509500/pthread-join-and-main-blocking-multithreading

以及相应的解释:

pthreads - Join on group of threads, wait for one to exit

根据建议的答案:

You'd need to create your own version of it - e.g. an array of flags (one flag per thread) protected by a mutex and a condition variable; where just before "pthread_exit()" each thread acquires the mutex, sets its flag, then does "pthread_cond_signal()". The main thread waits for the signal, then checks the array of flags to determine which thread/s to join (there may be more than one thread to join by then).

我试过如下:

我的状态数组,用于跟踪哪些线程已完成:

typedef struct {
    int Finish_Status[THREAD_NUM];
    int signalled;

    pthread_mutex_t mutex;
    pthread_cond_t FINISHED;
    }THREAD_FINISH_STATE;

线程例程,它在线程完成时设置相应的数组元素,并发出条件变量的信号:

void* THREAD_ROUTINE(void* arg)
{
    THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
    printf("Thread created with id %d\n",temp->id);
    waitFor(5);
    pthread_mutex_lock(&(ThreadFinishStatus.mutex));
    ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
    ThreadFinishStatus.signalled=TRUE;
    if(ThreadFinishStatus.signalled==TRUE)
    {
      pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
      printf("Signal that thread %d finished\n",temp->id);
     }
    pthread_mutex_unlock(&(ThreadFinishStatus.mutex));

    pthread_exit((void*)(temp->id));
    }

我无法编写相应的部分pthread_join()pthread_cond_wait()函数。有一些我无法实现的事情。

1)如何在我的pthread_cond_wait()中编写相应的部分main()

2)我试着把它写成:

   pthread_mutex_lock(&(ThreadFinishStatus.mutex));
    while((ThreadFinishStatus.signalled != TRUE){
     pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
     printf("Main Thread signalled\n");
     ThreadFinishStatus.signalled==FALSE; //Reset signalled
     //check which thread to join
    }
    pthread_mutex_unlock(&(ThreadFinishStatus.mutex)); 

但它没有进入while循环。

3)如何使用pthread_join()以便我可以获得存储在arg[i].returnStatus中的返回值 即在我的主要地方放置以下声明:

`pthread_join(T[i],&(arg[i].returnStatus));`

完整代码

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

#define THREAD_NUM 5
#define FALSE 0
#define TRUE 1


void waitFor (unsigned int secs) {
    time_t retTime;
    retTime = time(0) + secs;     // Get finishing time.
    while (time(0) < retTime);    // Loop until it arrives.
}

typedef struct {
    int Finish_Status[THREAD_NUM];
    int signalled;

    pthread_mutex_t mutex;
    pthread_cond_t FINISHED;
    }THREAD_FINISH_STATE;

typedef struct {
    int id;
    void* returnStatus;
    }THREAD_ARGUMENT;

THREAD_FINISH_STATE ThreadFinishStatus;

void initializeState(THREAD_FINISH_STATE* state)
{
 int i=0;
 state->signalled=FALSE;
 for(i=0;i<THREAD_NUM;i++)
 {
     state->Finish_Status[i]=FALSE;
     }
 pthread_mutex_init(&(state->mutex),NULL);
 pthread_cond_init(&(state->FINISHED),NULL);
    }

void destroyState(THREAD_FINISH_STATE* state)
{
 int i=0;
 for(i=0;i<THREAD_NUM;i++)
 {
     state->Finish_Status[i]=FALSE;
     }
 pthread_mutex_destroy(&(state->mutex));
 pthread_cond_destroy(&(state->FINISHED));
    }


void* THREAD_ROUTINE(void* arg)
{
    THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
    printf("Thread created with id %d\n",temp->id);
    waitFor(5);
    pthread_mutex_lock(&(ThreadFinishStatus.mutex));
    ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
    ThreadFinishStatus.signalled=TRUE;
    if(ThreadFinishStatus.signalled==TRUE)
    {
      pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
      printf("Signal that thread %d finished\n",temp->id);
     }
    pthread_mutex_unlock(&(ThreadFinishStatus.mutex));

    pthread_exit((void*)(temp->id));
    }

int main()
{
    THREAD_ARGUMENT arg[THREAD_NUM];
    pthread_t T[THREAD_NUM];
    int i=0;
    initializeState(&ThreadFinishStatus);

    for(i=0;i<THREAD_NUM;i++)
    {
        arg[i].id=i;
        }

    for(i=0;i<THREAD_NUM;i++)
        {
            pthread_create(&T[i],NULL,THREAD_ROUTINE,(void*)&arg[i]);
        }

    /*
     Join only if signal received
    */

    pthread_mutex_lock(&(ThreadFinishStatus.mutex));
    //Wait
    while((ThreadFinishStatus.signalled != TRUE){
     pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
     printf("Main Thread signalled\n");
     ThreadFinishStatus.signalled==FALSE; //Reset signalled
     //check which thread to join
    }
    pthread_mutex_unlock(&(ThreadFinishStatus.mutex));

    destroyState(&ThreadFinishStatus);
    return 0;
    }

4 个答案:

答案 0 :(得分:3)

这是一个程序示例,它使用计数信号量来观察线程完成,找出它是哪个线程,并查看该线程的一些结果数据。这个程序使用锁是有效的 - 服务员不会被虚假地唤醒(请注意,在他们已经发布保护共享状态的互斥锁之后,线程只会发布到信号量)。

这种设计允许主程序在线程完成后立即处理来自某些线程计算的结果,并且不需要主等待所有线程完成。如果每个线程的运行时间变化很大,这将特别有用。

最重要的是,这个程序不会死锁,也不会比赛。

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

void* ThreadEntry(void* args );

typedef struct {
    int threadId;
    pthread_t thread;
    int threadResult;
} ThreadState;

sem_t           completionSema;

pthread_mutex_t resultMutex;

std::queue<int> threadCompletions;

ThreadState* threadInfos;

int main() {

    int numThreads = 10;
    int* threadResults;
    void* threadResult;
    int doneThreadId;


    sem_init( &completionSema, 0, 0 );

    pthread_mutex_init( &resultMutex, 0 );

    threadInfos = new ThreadState[numThreads];

    for ( int i = 0; i < numThreads; i++ ) {

        threadInfos[i].threadId = i;
        pthread_create( &threadInfos[i].thread, NULL, &ThreadEntry, &threadInfos[i].threadId  );
    }

    for ( int i = 0; i < numThreads; i++ ) {
        // Wait for any one thread to complete; ie, wait for someone
        // to queue to the threadCompletions queue.
        sem_wait( &completionSema );


        // Find out what was queued; queue is accessed from multiple threads,
        // so protect with a vanilla mutex.
        pthread_mutex_lock(&resultMutex);
        doneThreadId = threadCompletions.front();
        threadCompletions.pop();
        pthread_mutex_unlock(&resultMutex);

        // Announce which thread ID we saw finish
        printf(
            "Main saw TID %d finish\n\tThe thread's result was %d\n",
            doneThreadId,
            threadInfos[doneThreadId].threadResult
        );

        // pthread_join to clean up the thread.
        pthread_join( threadInfos[doneThreadId].thread, &threadResult );
    }

    delete threadInfos;

    pthread_mutex_destroy( &resultMutex );
    sem_destroy( &completionSema );

}

void* ThreadEntry(void* args ) {
    int threadId = *((int*)args);

    printf("hello from thread %d\n", threadId );

    // This can safely be accessed since each thread has its own space
    // and array derefs are thread safe.
    threadInfos[threadId].threadResult = rand() % 1000;


    pthread_mutex_lock( &resultMutex );
    threadCompletions.push( threadId );
    pthread_mutex_unlock( &resultMutex );

    sem_post( &completionSema );

    return 0;
}

答案 1 :(得分:1)

Pthread条件没有“记忆”;如果在pthread_cond_wait之前调用pthread_cond_signal,则pthread_cond_wait不会返回,这就是为什么在调用pthread_cond_wait之前检查谓词很重要,如果它是真的则不调用它。但这意味着操作,在这种情况下“检查要连接的线程”应仅依赖于谓词,而不是取决于是否调用pthread_cond_wait。

另外,你可能想让while循环实际等待所有线程终止,你现在没有这样做。

(另外,我认为关于“signaled == FALSE”无害的另一个答案是错误的,它不是无害的,因为有一个pthread_cond_wait,当它返回时,signaled会变为true。)

因此,如果我想编写一个等待所有线程以这种方式终止的程序,它看起来更像是

pthread_mutex_lock(&(ThreadFinishStatus.mutex));
// AllThreadsFinished would check that all of Finish_Status[] is true
// or something, or simpler, count the number of joins completed
while (!AllThreadsFinished()) {
  // Wait, keeping in mind that the condition might already have been
  // signalled, in which case it's too late to call pthread_cond_wait,
  // but also keeping in mind that pthread_cond_wait can return spuriously,
  // thus using a while loop
  while (!ThreadFinishStatus.signalled) {
    pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
  }
  printf("Main Thread signalled\n");
  ThreadFinishStatus.signalled=FALSE; //Reset signalled
  //check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));

答案 2 :(得分:0)

您的代码显示正常。你有一个小小的bug:

 ThreadFinishStatus.signalled==FALSE; //Reset signalled

这没有任何作用。它测试signaled是否为FALSE并抛弃结果。这是无害的,因为你无需做任何事情。 (你永远想要将signalled设置为FALSE,因为它失去了它已经发出信号的事实。没有任何理由不信任它 - 如果一个线程完成,那么它永远完成了。)

未输入while循环意味着signalled为TRUE。这意味着线程已经设置了它,在这种情况下,没有必要进入循环,因为没有什么可以等待。这很好。

此外:

ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)

没有必要测试你刚设置的东西。它不像套装会失败。

FWIW,我建议重新设计。如果像pthread_join这样的现有功能没有完全符合您的要求,请不要使用它们。如果你将要有跟踪完成工作的结构,那么将它与线程终止完全分开。既然你已经知道做了什么工作,那么线程何时以及如何终止会有什么不同呢?不要认为这是“我需要一种特殊的方式来了解线程什么时候终止”,而是想到这个“我需要知道做了什么工作,所以我可以做其他事情。”

答案 3 :(得分:0)

你的代码很活泼。

假设您在main()中获取互斥锁之前启动了一个线程并完成了。您的while循环永远不会运行,因为退出主题已将signalled设置为TRUE

我将回应@ antiduh的建议,即使用信号量计算死亡但未连接的线程的数量。然后循环到生成等待信号量的线程数。我指出POSIX sem_tpthread_mutex不同,因为sem_wait可以返回EINTR。