在C++中,等待条件变量的线程可以通知自己吗?

问题描述 投票:0回答:1

我有一个

sender()
函数,它发送UDP数据包。在
sender()
结束时,它会唤醒接收器线程以超时等待 UDP 响应。

这里

sender()
可以由主线程或接收线程调用。接收线程在收到响应消息或超时后,可能会决定发送新的数据包。这就是为什么,
sender()
也应该能够从接收者的上下文中调用。伪代码如下:

std::mutex m;
std::conditional_variable reciever_cv;

void sender()
{
  request = create_new_packet();
  socket.sendBytes( request );
  receiver_cv.notify_one();
}

// receiver() gets started as a thread when system is up 
void receiver()
{
 while(true)
 {
  std::uniq_lock lock(m);
  receiver_cv.wait( lock, [](){ return predicate; }); // predicate could be anything
  socket.receiveBytes();

  // ... some processing
  if( new packet needs to be sent )
  {
    sender();
  }
 }
}

我的问题是线程可以在下一个循环中通知自己唤醒吗?
我的任务很简单。唯一的复杂之处是不同线程共享一个函数。我希望以某种方式记住唤醒次数,并且接收器只是唤醒以匹配该数字。

到目前为止,我浏览过的所有在线材料都给出了从单独线程发出通知的建议。

对于我的情况,计算信号量是更好的方法吗?

c++ multithreading
1个回答
0
投票

我的问题是线程可以在下一个循环中通知自己唤醒吗?

不,但您可以避免不必要的等待。 您的示例中严重缺少的一件事是典型的(原子)

bool
,它表明您是否应该等待:

std::mutex m;
std::conditional_variable reciever_cv;
std::atomic<bool> waiting_for_response = false;

void sender()
{
  request = create_new_packet();
  socket.sendBytes( request );
  // not sure about memory order tbh, let's just use the default
  // we could also use a non-atomic bool if we briefly locked the mutex here
  waiting_for_response = true;
  receiver_cv.notify_one();
}

void receiver()
{
 while(true)
 {
    std::unique_lock lock(m);
    receiver_cv.wait( lock, [](){ return waiting_for_response; });
    socket.receiveBytes();
    waiting_for_response = false;

    // ...
    sender(); // safe

调用

sender()
现在是安全的,根本不需要锁等待,因为在调用
wait()
之前会检查谓词(没有谓词)。 这可能就是涵盖您的用例所需的全部内容。 无论如何,您通常都需要这样的
bool
来处理虚假唤醒。

但是,这个设计还是有很大缺陷的。最大的问题是,当接收者已经在等待时调用

sender()
时,它无法正确处理,因此你一次只能等待一个数据包。 实际上,您需要像
std::counting_semaphore
这样的东西来实现具有多个元素的适当的单一生产者、单一消费者设计。

如果您简单地使用 C++20 中添加的

std::atomic<bool>::wait
/
std:atomic<bool>::notify
,您还可以摆脱条件变量和互斥体。 另请参见 std::atomic::wait 与 std::condition_variable::wait

© www.soinside.com 2019 - 2024. All rights reserved.