在pthread中,如何可靠地传递信号到另一个线程? [英] In pthread, how to reliably pass signal to another thread?

查看:152
本文介绍了在pthread中,如何可靠地传递信号到另一个线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在pthread中编写一个简单的线程池程序。但是,看来 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确保他已准备好被释放
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不要花太长时间准备好。否则我会错过
//唤醒调用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;
}

XXX 标记,如果我取走 sleep 调用,则 main()可能会失败,因为它错过了从 liberator()唤醒呼叫。当然, sleep 不是一个非常可靠的方法来确保。



在现实生活中,将是一个工作线程告诉管理器线程它准备工作,或者管理器线程宣布新的工作是可用的。



如何在pthread ? b b b 但他对这个问题的解释可能会更好。我建议任何人看这个问题阅读评论中的讨论,以了解发生了什么。



特别是,我自己会修改他的答案和代码示例,使这更清楚。 (因为Borealid的原始答案,虽然编译和工作,困惑了我很多)

  //在主
pthread_mutex_lock & my_cond_m);

//如果没有设置标志,意味着liberator没有运行
//。我将通过pthread的信号等待他
//机制

//如果_is_设置,意味着liberator已经运行。我简单地
//跳过等待,因为我已经同步。我不需要
//使用pthread的信号机制
if(!flag)pthread_cond_wait(& my_cond,& my_cond_m);

pthread_mutex_unlock(& my_cond_m);

//在解放线程
pthread_mutex_lock(& my_cond_m);

//告诉任何正在睡觉的人。如果没有人在睡觉,
//他们应该检查这个标志,表示我已经
//发送信号。这是必需的,因为pthread的信号
//不像消息队列 - 如果
//没有人等待发送的条件,发送的信号丢失。
//你可以认为这个标志是一个持久信号
flag = 1;
pthread_cond_signal(& my_cond);
pthread_mutex_unlock(& my_cond_m);


解决方案

使用同步变量。



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

在主题中:

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

对于生产者 - 消费者问题,这将是消费者在缓冲区为空时休眠,生产者睡觉时,它是满的。请记住在访问全局变量之前获取锁


I'm trying to write a simple thread pool program in pthread. However, it seems that pthread_cond_signal doesn't block, which creates a problem. For example, let's say I have a "producer-consumer" program:

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;
}

As described in the two XXX marks, if I take away the sleep calls, then main() may stall because it has missed the wake up call from liberator(). Of course, sleep isn't a very robust way to ensure that either.

In real life situation, this would be a worker thread telling the manager thread that it is ready for work, or the manager thread announcing that new work is available.

How would you do this reliably in pthread?


Elaboration

@Borealid's answer kind of works, but his explanation of the problem could be better. I suggest anyone looking at this question to read the discussion in the comments to understand what's going on.

In particular, I myself would amend his answer and code example like this, to make this clearer. (Since Borealid's original answer, while compiled and worked, confused me a lot)

// 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);

解决方案

Use a synchronization variable.

In main:

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

In the thread:

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

For a producer-consumer problem, this would be the consumer sleeping when the buffer is empty, and the producer sleeping when it is full. Remember to acquire the lock before accessing the global variable.

这篇关于在pthread中,如何可靠地传递信号到另一个线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆