如何正确使用互斥量?
How to use mutex properly?
我有 mailBox class,线程之间共享发送和接收方法,线程:线程 1 发送消息,线程 2 和 3 接收消息,我必须如何使用互斥锁来同步它?
我尝试过的任何组合都没有成功。
std::mutex g_lock; //in global
void sendMessage(Message msg) {
if (g_lock.try_lock()) {
this_thread::sleep_for(100ms); // DELAY
messages->push_back(msg);
g_lock.unlock();
}
}
接收方法相同
完整代码:
https://pastebin.com/7y2RC5br
此外,此代码无法调试,因为延迟会更改代码的逻辑。
代码的正确逻辑:
thread2/3 尝试锁定并读取消息,清空然后解锁
thread1 尝试锁定并发送消息然后解锁
thread2/3 尝试锁定并读取消息,获取消息并写入文件然后解锁
当我尝试从线程 2/3 中使用互斥锁 try_lock 时,我的线程一直被阻塞,而线程 1 在所有线程 2/3 之后一直在工作。
将低级互斥量装入构建块类型。
基于锁的线程安全非常容易出错。它不仅脆弱,而且无法组合;成对线程安全的三个例程在组合时可能不安全。
线程安全是一种关系属性,而不是绝对的。
有多种已知模式已被数学证明有效。正确实施,你就不会那么注定。把一些东西放在一起,你的代码就不会正确。
要设计新的线程代码,您需要擅长基于证明的计算机科学。实施比正确设计更容易。
对于您的情况,我将从线程安全队列原语开始。您将需要条件变量、互斥量和标准双端队列。然后将每个例程连接到队列的一端,并向另一端发送消息。 (reader 只应从队列中读取并按顺序使用每条消息;编写器只应在队列中发送消息)。
我的意思是,这仍然很难做到正确,但至少你的基元不是原始互斥体。
template<class T>
struct threadsafe_queue {
T pop();
void push(T);
std::deque<T> pop_all();
std::optional<T> try_pop();
template<class...Ts>
std::optional<T> wait_for_pop( std::chrono::duration<Ts...> );
private:
mutable std::mutex m;
std::condition_variable cv;
std::deque<T> queue;
std::unique_lock<std::mutex> lock() const;
};
我有 mailBox class,线程之间共享发送和接收方法,线程:线程 1 发送消息,线程 2 和 3 接收消息,我必须如何使用互斥锁来同步它?
我尝试过的任何组合都没有成功。
std::mutex g_lock; //in global
void sendMessage(Message msg) {
if (g_lock.try_lock()) {
this_thread::sleep_for(100ms); // DELAY
messages->push_back(msg);
g_lock.unlock();
}
}
接收方法相同
完整代码: https://pastebin.com/7y2RC5br
此外,此代码无法调试,因为延迟会更改代码的逻辑。
代码的正确逻辑: thread2/3 尝试锁定并读取消息,清空然后解锁 thread1 尝试锁定并发送消息然后解锁 thread2/3 尝试锁定并读取消息,获取消息并写入文件然后解锁
当我尝试从线程 2/3 中使用互斥锁 try_lock 时,我的线程一直被阻塞,而线程 1 在所有线程 2/3 之后一直在工作。
将低级互斥量装入构建块类型。
基于锁的线程安全非常容易出错。它不仅脆弱,而且无法组合;成对线程安全的三个例程在组合时可能不安全。
线程安全是一种关系属性,而不是绝对的。
有多种已知模式已被数学证明有效。正确实施,你就不会那么注定。把一些东西放在一起,你的代码就不会正确。
要设计新的线程代码,您需要擅长基于证明的计算机科学。实施比正确设计更容易。
对于您的情况,我将从线程安全队列原语开始。您将需要条件变量、互斥量和标准双端队列。然后将每个例程连接到队列的一端,并向另一端发送消息。 (reader 只应从队列中读取并按顺序使用每条消息;编写器只应在队列中发送消息)。
我的意思是,这仍然很难做到正确,但至少你的基元不是原始互斥体。
template<class T>
struct threadsafe_queue {
T pop();
void push(T);
std::deque<T> pop_all();
std::optional<T> try_pop();
template<class...Ts>
std::optional<T> wait_for_pop( std::chrono::duration<Ts...> );
private:
mutable std::mutex m;
std::condition_variable cv;
std::deque<T> queue;
std::unique_lock<std::mutex> lock() const;
};