c++ mutex 可以跨 method/variable 吗?如果是这样,为什么它在这里不起作用?
Can c++ mutex cross method/variable? If so, why does it not work here?
我正在编写一个提供者-消费者程序。有很多消息队列,我想确保每个消息队列中入队的每条消息都有一个顺序递增的索引,例如<0, "msga">, <1, "msgb">, ...
。每个队列内部保持顺序,不同队列无关
我使用 2 个哈希映射和 2 个互斥锁来执行此操作(我只想使用一个锁,但失败了)。
(i) 第一个hash map将队列名映射到一对<int, mutex *>
,其中int
表示每个队列的计数器,mutex在并发请求中保护队列。定义是
using umap_cnt = unordered_map<string, pair<int, mutex* > >;
umap_cnt counters;
(ii) 第二个hash map将queue name映射到实际消息<int, MSG>
(MSG实际上是string),定义为
using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
umap_msg messages`;
我的逻辑是
- 在
counters
中找到一个队列的互斥锁,lock()它
- 使用 counter_iter->first 作为消息的索引,将其放入
messages
- 增加指数
- unlock() 互斥锁
示例代码如下
/* File A.cpp */
using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
mutex mtx;
umap_msg messages;
void put(string kname, MSG msg, int index) {
// If not using mtx here, the message would be out of order.
// lock_guard<mutex> mtx;
messages[kname].push_back(make_pair<index, msg>);
}
// Many threads runs producer()
/* File B.cpp*/
using umap_cnt = unordered_map<string, pair<int, mutex* > >
void producer(string kname, MSG msg) {
umap_cnt::iterator iter = counters.find(kname);
if (iter == counters.end())
return;
// lock the queue
iter->second.second->lock();
put(kname, msg, iter->second.first);
++iter->second.first; // increase the counter
iter->second.second->unlock();
}
问题是我发现单锁不起作用。我必须使用 2 个互斥锁,一个在生产者中,另一个在输入中,否则我会收到乱序消息或分段错误(不知道为什么)。
我最初的目的是在生产者中只使用一把锁。每个队列都有自己的互斥锁,任何两个线程都不能同时获得一个队列的锁,所以每个队列中的每条消息都应该是有序的。然而,结果并不是我所期望的。
为什么第 7 行需要额外的锁?如果我必须使用 2 个锁,我是否可以优化它,因为 2 个锁似乎有点重?
我假设名为 messages
的 unordered_map
一开始是空的(顺便说一句,我假设正确还是代码没有显示这部分?),然后在第 8 行:
messages[kname].push_back(make_pair<index, msg>);
我们使用 [] operator 写入 messages
,如果键不存在则执行插入。
并且不支持并发写入 unordered_map
(参见 this question),因此需要一个互斥体来使这些写入顺序进行。
我正在编写一个提供者-消费者程序。有很多消息队列,我想确保每个消息队列中入队的每条消息都有一个顺序递增的索引,例如<0, "msga">, <1, "msgb">, ...
。每个队列内部保持顺序,不同队列无关
我使用 2 个哈希映射和 2 个互斥锁来执行此操作(我只想使用一个锁,但失败了)。
(i) 第一个hash map将队列名映射到一对<int, mutex *>
,其中int
表示每个队列的计数器,mutex在并发请求中保护队列。定义是
using umap_cnt = unordered_map<string, pair<int, mutex* > >;
umap_cnt counters;
(ii) 第二个hash map将queue name映射到实际消息<int, MSG>
(MSG实际上是string),定义为
using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
umap_msg messages`;
我的逻辑是
- 在
counters
中找到一个队列的互斥锁,lock()它 - 使用 counter_iter->first 作为消息的索引,将其放入
messages
- 增加指数
- unlock() 互斥锁
示例代码如下
/* File A.cpp */
using umap_msg = unordered_map<string, vector<pair<int, msg> > >;
mutex mtx;
umap_msg messages;
void put(string kname, MSG msg, int index) {
// If not using mtx here, the message would be out of order.
// lock_guard<mutex> mtx;
messages[kname].push_back(make_pair<index, msg>);
}
// Many threads runs producer()
/* File B.cpp*/
using umap_cnt = unordered_map<string, pair<int, mutex* > >
void producer(string kname, MSG msg) {
umap_cnt::iterator iter = counters.find(kname);
if (iter == counters.end())
return;
// lock the queue
iter->second.second->lock();
put(kname, msg, iter->second.first);
++iter->second.first; // increase the counter
iter->second.second->unlock();
}
问题是我发现单锁不起作用。我必须使用 2 个互斥锁,一个在生产者中,另一个在输入中,否则我会收到乱序消息或分段错误(不知道为什么)。
我最初的目的是在生产者中只使用一把锁。每个队列都有自己的互斥锁,任何两个线程都不能同时获得一个队列的锁,所以每个队列中的每条消息都应该是有序的。然而,结果并不是我所期望的。
为什么第 7 行需要额外的锁?如果我必须使用 2 个锁,我是否可以优化它,因为 2 个锁似乎有点重?
我假设名为 messages
的 unordered_map
一开始是空的(顺便说一句,我假设正确还是代码没有显示这部分?),然后在第 8 行:
messages[kname].push_back(make_pair<index, msg>);
我们使用 [] operator 写入 messages
,如果键不存在则执行插入。
并且不支持并发写入 unordered_map
(参见 this question),因此需要一个互斥体来使这些写入顺序进行。