English 中文(简体)
在校正,如何可靠地将信号传递给另一个深层?
原标题:In pthread, how to reliably pass signal to another thread?

I m试图在校读简单的校对池方案。 但是,看来<代码>pthread_cond_signal。 这造成了问题。 例如,我要说的是“生产者-消费者”方案:

pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t my_cond_m = PTHREAD_MUTEX_INITIALIZER;

void * liberator(void * arg)
{
    // XXX make sure he is ready to be freed
    sleep(1);

    pthread_mutex_lock(&my_cond_m);
    pthread_cond_signal(&my_cond);
    pthread_mutex_unlock(&my_cond_m);

    return NULL;
}

int main()
{
    pthread_t t1;
    pthread_create(&t1, NULL, liberator, NULL);

    // XXX Don t take too long to get ready. Otherwise I ll miss 
    // the wake up call forever
    //sleep(3);

    pthread_mutex_lock(&my_cond_m);
    pthread_cond_wait(&my_cond, &my_cond_m);
    pthread_mutex_unlock(&my_cond_m);

    pthread_join(t1, NULL);

    return 0;
}

如我删除<编码>sleep。 电话:main()可能受阻,因为它没有从<代码>liberator()上接过电话。 当然,sleep 这对于确保两者都不会有那么强。

在现实生活中,这将是一位工人对管理人员说,他们已经做好了工作准备,或者管理人员已经宣布新的工作是可用的。

你们如何在read子里可靠地这样做?


Elaboration

@Borealid 回答类型的工作,但他对这个问题的解释可能更好。 我建议,研究这一问题的任何人在评论中阅读讨论,以了解正在发生什么。

我尤其要修改他的回答和照例,使这一点更加明确。 (Since Borealid的原始答复,虽然编辑和工作,但混淆了我的许多工作)

// In main
pthread_mutex_lock(&my_cond_m);

// If the flag is not set, it means liberator has not 
// been run yet. I ll wait for him through pthread s signaling 
// mechanism

// If it _is_ set, it means liberator has been run. I ll simply 
// skip waiting since I ve already synchronized. I don t need to 
// use pthread s signaling mechanism
if(!flag) pthread_cond_wait(&my_cond, &my_cond_m);

pthread_mutex_unlock(&my_cond_m);

// In liberator thread
pthread_mutex_lock(&my_cond_m);

// Signal anyone who s sleeping. If no one is sleeping yet, 
// they should check this flag which indicates I have already 
// sent the signal. This is needed because pthread s signals 
// is not like a message queue -- a sent signal is lost if 
// nobody s waiting for a condition when it s sent.
// You can think of this flag as a "persistent" signal
flag = 1;
pthread_cond_signal(&my_cond);
pthread_mutex_unlock(&my_cond_m);
最佳回答

使用同步变量。

http://www.un.org/Depts/DGACM/index_spanish.htm

pthread_mutex_lock(&my_cond_m);
while (!flag) {
    pthread_cond_wait(&my_cond, &my_cond_m);
}
pthread_mutex_unlock(&my_cond_m);

read:

pthread_mutex_lock(&my_cond_m);
flag = 1;
pthread_cond_broadcast(&my_cond);
pthread_mutex_unlock(&my_cond_m);

对于生产者-消费者问题,在缓冲空闲时,消费者会睡觉,而生产者则会睡觉。 查阅全球变量的前<>。

问题回答

我找到了以下解决办法:here。 对我来说,理解问题的trick计是:

  1. Producers and consumers must be able to communicate both ways. Either way is not enough.
  2. This two-way communication can be packed into one pthread condition.

为了说明这一点,上述博客员额表明,这是实际上有意义和可取的行为:

pthread_mutex_lock(&cond_mutex);
pthread_cond_broadcast(&cond):
pthread_cond_wait(&cond, &cond_mutex);
pthread_mutex_unlock(&cond_mutex);

想法是,如果生产者和消费者都采用这一逻辑,他们当中任何一方都能够首先睡觉,因为两者都能发挥相互的作用。 换言之,如果消费者需要睡觉,它会因为生产者需要醒来,反之亦然。 把这种逻辑归为一种单纯的条件,是有意义的。

当然,上述法典有无意的行为,即当工人实际上想要赶上生产者时,便会把另一个睡觉的工人 wake起来。 如@Borealid建议的那样:

while(!work_available) pthread_cond_wait(&cond, &cond_mutex);

在工人广播时,所有工人的校对都将是一只(由于在<条码>上的暗中锁定——cond_wait)。 由于一名工人的read子将消费工作(work_ Available re to false),而其他工人则照觉醒并实际工作,因此无法再工作,因此该工人将再次睡觉。

在这里,对感兴趣的任何人进行了I号评论测试:

// gcc -Wall -pthread threads.c -lpthread

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

pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t my_cond_m = PTHREAD_MUTEX_INITIALIZER;

int * next_work = NULL;
int all_work_done = 0;

void * worker(void * arg)
{
    int * my_work = NULL;

    while(!all_work_done)
    {
        pthread_mutex_lock(&my_cond_m);

        if(next_work == NULL)
        {
            // Signal producer to give work
            pthread_cond_broadcast(&my_cond);

            // Wait for work to arrive
            // It is wrapped in a while loop because the condition 
            // might be triggered by another worker thread intended 
            // to wake up the producer
            while(!next_work && !all_work_done)
                pthread_cond_wait(&my_cond, &my_cond_m);
        }

        // Work has arrived, cache it locally so producer can 
        // put in next work ASAP
        my_work = next_work;
        next_work = NULL;
        pthread_mutex_unlock(&my_cond_m);

        if(my_work)
        {
            printf("Worker %d consuming work: %d
", (int)(pthread_self() % 100), *my_work);
            free(my_work);
        }
    }

    return NULL;
}

int * create_work()
{
    int * ret = (int *)malloc(sizeof(int));
    assert(ret);
    *ret = rand() % 100;
    return ret;
}

void * producer(void * arg)
{
    int i;

    for(i = 0; i < 10; i++)
    {
        pthread_mutex_lock(&my_cond_m);
        while(next_work != NULL)
        {
            // There s still work, signal a worker to pick it up
            pthread_cond_broadcast(&my_cond);

            // Wait for work to be picked up
            pthread_cond_wait(&my_cond, &my_cond_m);
        }

        // No work is available now, let s put work on the queue
        next_work = create_work();
        printf("Producer: Created work %d
", *next_work);

        pthread_mutex_unlock(&my_cond_m);
    }

    // Some workers might still be waiting, release them
    pthread_cond_broadcast(&my_cond);

    all_work_done = 1;
    return NULL;
}

int main()
{
    pthread_t t1, t2, t3, t4;

    pthread_create(&t1, NULL, worker, NULL);
    pthread_create(&t2, NULL, worker, NULL);
    pthread_create(&t3, NULL, worker, NULL);
    pthread_create(&t4, NULL, worker, NULL);

    producer(NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    return 0;
}




相关问题
Silverlight, Updating the UI during processing

I have a simple silverlight multifile upload application, and i want to provide the user with some feedback, right now its only in a test phase and i dont have the webservice. Somehow i cant get the ...

Is reading from an XmlDocument object thread safe?

I was wondering if i could safely read from an XmlDocument object using SelectNodes() and SelectSingleNode() from multiple threads with no problems. MSDN says that they are not guaranteed to be ...

Terminating a thread gracefully not using TerminateThread()

My application creates a thread and that runs in the background all the time. I can only terminate the thread manually, not from within the thread callback function. At the moment I am using ...