- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
考虑以下代码
#include <thread>
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
template <typename T>
class Tqueue
{
public:
Tqueue() : m_next_ticket(0),
m_counter(0) {}
void push(const T& e){
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.push(e);
lock.unlock();
m_cond.notify_all();
};
T wait_and_pop() {
std::unique_lock<std::mutex> lock(m_mutex);
int ticket = m_next_ticket++;
m_cond.wait(lock,[=]{return (!m_queue.empty())
&& (ticket == m_counter);});
m_counter++;
T data = m_queue.front();
m_queue.pop();
return data;
}
private:
int m_next_ticket;
int m_counter;
std::queue<T> m_queue;
std::mutex m_mutex;
std::condition_variable m_cond;
};
这应该是我想出的公平队列的模板。在这种情况下,公平意味着 wait_and_pop() 调用返回的顺序与不同线程调用它们的顺序相同。
例如:线程 1 在空队列上调用 wait_and_pop() 并阻塞。然后 Thread 2 在空队列上调用 wait_and_pop() 并阻塞。之后 Thread 3 使用 push() 推送两个事件。现在 Thread 1 应该在 Thread 2 之前返回。
使用以下代码,有时它会起作用。但大多数时候代码永远阻塞:
Tqueue<int> queue;
std::mutex mutex;
void test(int i)
{
auto bla = queue.wait_and_pop();
std::cout << "Thread : "<<bla << std::endl;
}
const int SIZE = 200;
int main(int argc, char *argv[])
{
std::vector<std::thread> threads;
for(int i = 0; i < SIZE; ++i)
threads.push_back(std::thread(test,i));
for(int i = 0; i < SIZE; ++i)
queue.push(i);
for(int i = 0; i < SIZE; ++i)
threads[i].join();
return 0;
}
想法是为每个线程创建一个唯一的票证。使用条件变量,然后我们在 wait_and_pop() 函数中等待,直到插入一个新事件。在 push() 函数中,新事件被插入队列并通知所有等待线程。每个线程检查是否队列不再为空并且唯一票证等于当前柜台。如果是这样,特定线程离开条件循环,从队列中弹出当前事件并增加计数器。
我怀疑有些通知丢失了,但我无法理解为什么会这样。有什么想法可以解决这个问题或如何以正确的方式实现这个问题吗?
编辑我如下更改了队列中的代码。现在它似乎工作。重要的是,我通知,同时仍然持有锁(在 push() 和 wait_and_pop() 中)。此外,我将票证系统更改为线程 ID 队列,但这只是为了方便,它使源代码保持紧凑。但我不确定,如果我想在生产代码,因为我不明白为什么它现在可以工作,而且我不知道它是否适用于所有情况。也许有人可以对此发表评论?
template <typename T>
class Tqueue
{
public:
void push(const T& e){
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.push(e);
m_cond.notify_all();
};
T wait_and_pop() {
std::unique_lock<std::mutex> lock(m_mutex);
m_ids.push(std::this_thread::get_id());
m_cond.wait(lock,[=]{return (!m_queue.empty())
&& (m_ids.front() == std::this_thread::get_id());});
T data = m_queue.front();
m_queue.pop();
m_ids.pop();
m_cond.notify_all();
return data;
}
private:
std::queue<T> m_queue;
std::queue<std::thread::id> m_ids;
std::mutex m_mutex;
std::condition_variable m_cond;
};
最佳答案
通知确实丢失了。有可能许多 push
生成更少数量的线程被唤醒,因为当 m_cond.notify_all();
被执行时,它只是让等待线程 runnable,即准备运行。这些线程仍然需要等待并获取 m_cond.wait
中的锁。
也有可能是主线程在单个 等待线程最终可以执行之前继续多次获取互斥量。这导致通知饥饿。
为了使该机制发挥作用,您需要在条件受到影响时随时通知。您已经通知 m_queue.push(e);
,这会影响第一个条件 !m_queue.empty()
。您还需要在 wait_and_pop
结束时通知,以处理第二个条件 ticket == m_counter
。
T wait_and_pop() {
....blah blah
T data = m_queue.front();
m_queue.pop();
lock.unlock();
m_cond.notify_all();
return data;
}
注意:有可能
在这里我的意思是“最终会有一个最终发生的线程调度”。我不是说“我不确定”。
进一步说明:condition_variable.notify_all()
只保证最终唤醒线程。它不保证 X
次调用会唤醒 X
次。此外,由于您的情况,减少了保证只通知一个线程,这是根本原因。
关于在wait_and_pop解锁前后通知
在 wait_and_pop
中释放锁之前或之后通知应该没有任何区别。我指定的修改应该与编辑中的修改一样。我一直在进行一些变化(线程数、等待 x 线程完成并再次推送)的测试,结果相同。
关于c++ - 公平队列丢失通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32332926/
我有一个应用程序应该在应用程序处于前台和后台(不在历史记录中)时显示提醒通知。 在前景情况下,我通过以下方法实现了这一点。 PendingIntent pendingIntent = PendingI
如何为我的 WPF 应用程序创建通知,例如浏览器上的通知,它们通过浏览器顶部的“工具栏”显示消息或通过在右下角向上/向下滑动的弹出窗口显示“MSN”样式通知屏幕。也许在应用程序中心淡入/淡出的面板可以
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
我正在使用 Redis 作为分布式缓存。我有不同的应用程序,它们只听特定的键。例如:App1 听 App1.*App2 监听 App2.* 等等。 我的应用程序使用以下模式接收通知:App1:“ ke
我正在尝试构建一个基于官方节点 docker 镜像的 docker 镜像,我想知道是否有某种方法可以在推送新版本的官方节点镜像时自动重建镜像。这样我的图像就不会基于过时的基础图像。 也许有类似 rss
我在一个项目中工作,我需要在添加或修改文件时在数据库中记录文件信息,以便它们保持同步。这些文件应该存储在 Nextcloud 服务器中,那么 Nextcloud 是否有办法通知这些更改(例如 webh
通知类中的方法via 如何根据用户的偏好动态变化,一个用户可能想通过电子邮件接收,而另一个用户则不想 public function via($notifiable) { return ['d
我有一个应用程序,我正在发送推送通知,如果用户登录到应用程序,这很好 - 但是,如果他们没有/如果他们没有在 X 分钟内阅读通知,我想给他们发送一封电子邮件. 我要解决的方法是使用 Laravel N
我正在使用 Django 的 contrib.comments 并想了解以下内容。 是否有任何实用程序或应用程序可以插入到某个应用程序中,当对某个项目发表评论时向您发送通知? 我并没有真正使用过那么多
我希望用户在启动应用程序之前接受协议(protocol)。所以在 appDelegate.m 中我有以下内容: - (BOOL)application:(UIApplication *)applica
我正在创建一个新指令,我想知道如何在 angular 从 DOM 中删除元素时收到通知。 我的目标是在删除元素时添加 jquery 动画。 最佳答案 如果您尝试对元素的移除进行动画处理,则需要在移除元
我正在编写一个应用程序,其工作方式与Apple的Weather.app非常相似:底部有一个UIPageControl,屏幕中间有一个UIScrollView。在我的代码中,我实现了 - (void)s
如何查明 iPhone 注册了哪些通知? 例如: notify_post("com.apple.springboard/Prefs"); 最佳答案 虽然这个问题的答案已经得到确认,但由于 @Nate
我的 Cocoa 应用程序中有一个 TextField。该文本字段有时会被填充,有时会为空。 我希望当字段为空时按钮被禁用。现在,每当我对 Core Data 执行某些操作时,我都会检查该字段,Tex
我的应用程序在其数据库中包含文档。用户可以打开文档,在这种情况下,文档将保存到临时文件夹并在用户计算机上打开。 我希望在这些临时文件之一发生更改时收到通知,并让用户将更改后的文档保存回数据库。 在 D
我目前正在开发一个网络应用程序,它不断对 php 进行 ajax 调用(轮询),以从数据库中提取新的“任务”,有点像 gmail/facebook 检查新电子邮件和消息的方式。当前的 JavaScri
我正在尝试让通知适用于我使用 Angular 5 和 Electron 制作的 Electron 应用程序。到目前为止,我的 index.html 文件中有以下代码: function doNo
我有一个录音/播放应用程序。它在后台运行。当它进入后台时,如果任何其他音频应用程序打开或开始使用音频资源,我想适本地处理我的应用程序。 iOS 提供了一种发送此类通知的方法,如在 ipod 播放器中看
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
是否有 Subversion 的工具可以在对某些文件提交更改时自动通知我? 最佳答案 您可以创建一个 post-commit hook script “ Hook ”提交。 在钩子(Hook)脚本中,
我是一名优秀的程序员,十分优秀!