我有一个
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();
}
}
}
我的问题是线程可以在下一个循环中通知自己唤醒吗?
我的任务很简单。唯一的复杂之处是不同线程共享一个函数。我希望以某种方式记住唤醒次数,并且接收器只是唤醒以匹配该数字。
到目前为止,我浏览过的所有在线材料都给出了从单独线程发出通知的建议。
对于我的情况,计算信号量是更好的方法吗?
我的问题是线程可以在下一个循环中通知自己唤醒吗?
不,但您可以避免不必要的等待。 您的示例中严重缺少的一件事是典型的(原子)
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