在不使用互斥锁或全局变量的情况下停止所有pthread的好方法是什么?

时间:2016-11-08 11:57:27

标签: c pthreads

假设您不知道mutex_locks并且您不允许在程序中使用全局变量,如果返回成功的变量,您可以做什么来停止所有正在运行的pthread?

例如,您有一个传递给包含以下内容的pthread的数据结构:

typedef struct {

    char * string1;         //info from argv[1]
    char * string2;         //info from argv[2]

    int id;                 //thread id

} dataStruct;

在main.c中创建pthread时,你可以这样创建它们:

dataStruct dataStr[nbThread];           //array of dataStructs for each thread
pthread_t tabThread[nbThread];          //Pointers for thread 1

for (int i = 0; i < nbThread; ++i) {    //initiation of threads...
    dataStr[i].string1 = argv[1];

    pthread_create(&tabThread[i], NULL, thread, (void *)&dataStr[i]);   //create pthreads and
}   

for (int i = 0; i < nbThread; ++i) {
    pthread_join(tabThread[i], (void**)&(ptr[i]));                      //join threads
    //printf("\n return value from thread[%d] is [%d]\n",i, *ptr[i]);
}

现在其中一个线程找到了您希望实现的内容,如何让所有线程同时停止?

我可以在struct中指向一个指向main中的变量的指针,一旦线程成功就可以将其更改为true吗?

我可以使用pthreads的返回值以某种方式阻止它们吗?

我对指针的理解有点困难。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:0)

这是如何使用POSIX线程实现您的目标:

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

#define NUM_THREADS 10

pthread_mutex_t cv_mutex;
pthread_cond_t notification_cv;
pthread_t threads[NUM_THREADS];

bool allfinished = false;

void *worker(void *arg) {
    /* Allow cancellation, */
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    /* and get canceled at any time, not just at cancellation points: */
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

    int loop = 0;

    while (true) {
        printf("iteration %d\n", loop);
        ++loop;

        /* Do some "work": */
        ;

        /* We specifically assume the only shared state
         * is the condition variable, and that the workers
         * share NO OTHER STATE.
         * If they do, adjust the critical section accordingly,
         * perhaps with a 2nd mutex.
         */
        pthread_mutex_lock(&cv_mutex);
        if (loop > 5) { /* Simulate "work end" */
            allfinished = true;
            pthread_cond_broadcast(&notification_cv);
            pthread_mutex_unlock(&cv_mutex);
            pthread_exit(NULL);
        }
        pthread_mutex_unlock(&cv_mutex);
    }
    pthread_exit(NULL);
}

void *master(void *t) {
    /* Lock mutex and wait for signal. */
    pthread_mutex_lock(&cv_mutex);

    /* Loop because a thread might be awoken from its
     * waiting state even though no thread signalled
     * the condition variable:
     */
    while (!allfinished)
        pthread_cond_wait(&notification_cv, &cv_mutex);
    printf("master: woken up.\n");

    /* Unlocking the mutex allows workers to signal the condition variable again,
     * but this is irrelevant as we're heading for end-of-life:
     */
    pthread_mutex_unlock(&cv_mutex);

    for (size_t i = 0; i < NUM_THREADS - 1; ++i) {
        pthread_cancel(threads[i]);
    }

    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
    pthread_attr_t attr;

    /* Initialize mutex and condition variable objects */
    pthread_mutex_init(&cv_mutex, NULL);
    pthread_cond_init(&notification_cv, NULL);

    /* For portability, explicitly create threads in a joinable state: */
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    /* Keep a separate `master` thread, which may be doing other bookkeeping: */
    pthread_t s;
    pthread_create(&s, &attr, master, NULL);

    for(size_t i = 0; i < sizeof threads / sizeof *threads; ++i) {
        if (!pthread_create (&threads[i], &attr, worker, NULL) ) {
            printf("worker %zu created\n", i);
        }
    }

    /* Wait for all threads to complete. This will not wait forever because the master
     * thread will cancel all of the workers:
     */
    for (size_t i = 0; i < sizeof threads / sizeof *threads; ++i) {
        pthread_join(threads[i], NULL);
        printf("worker %zu done\n", i);
    }
    pthread_join(s, NULL);
    printf("master done\n");

    /* Clean up and exit */
    pthread_attr_destroy(&attr);
    pthread_mutex_destroy(&cv_mutex);
    pthread_cond_destroy(&notification_cv);
    pthread_exit(NULL);
}

答案 1 :(得分:-1)

我还不能评论,所以我会回复:

我认为您可以简单地使用main中定义的布尔值,并将其作为引用/指针传递给您的线程。

然后,当你的一个线程结束时,它必须更改此变量值以通知所有其他线程。因此,他们必须在其流程循环中检查此变量的状态,以便从中断。

如果使用C11和_Atomic关键字,那么对布尔值的这些操作应该没有并发/数据竞争问题(由@EOF表示高)#。

最后,你的循环调用pthread_join将使你的程序等到每个线程都干净地返回。

答案 2 :(得分:-3)

所以我最终找到了答案。它比我想象的要简单得多。

所以在我的主要内容中我创造了一个&#34;标志&#34;变量如此:

int flag = 0;

然后在我的结构中添加了以下指针:

int * ptrTrouve;        //ptr on address of flag in main.c

然后在创建所有pthread时,在传递pthread_create参数中的结构之前,我让ptrTrouve指向该标志的地址。我是这样做的

for (int i = 0; i < nbThread; ++i) {            //initiation of threads...

    dataStr[i].id    = i;                       //thread ID in appropriate struct

    dataStr[i].ptrTrouve = &flag;               //where the value of flag is stored

    pthread_create(&tabThread[i], NULL, thread, (void *)&dataStr[i]);   //create pthreads and
}   

最后在我的帖子中,当函数同时运行时,它们会永久验证是否:

*(dataStr.ptrTrouve) == 0

如果其中一个线程成功,它们会改变标志的值,如下所示:

*(dataStr.ptrTrouve) = 1;

当每个线程不断监视标志的值(*(dataStr.ptrTrouve))时,它们都可以同时运行。一旦标志改变,就会发生这种情况:

if(*(dataStr.ptrTrouve) == 1){              //if successful 
    pthread_exit(NULL);
}

我希望这个解决方案可以在将来帮助其他人。