我发现std::mutexVisual Studio 2013 中的实现太慢了.它使用重量级互斥锁,以确保即使在完全正常和花花公子的过程之间也可以实现同步; 除非你没有与其他进程交谈,并且可以真正使用CRITICAL_SECTION它在Win32上的自旋锁定优惠的额外速度.
我试图实现一个fast_recursive_mutex符合C++ 11互斥概念的东西,并且根据规范履行所有义务.从各方面来说,std::mutex只要您没有在进程之间进行同步,它就是替代品.
它与std::lock_guard和std::unique_lock.但是我在尝试使用它时会遇到问题,std::condition_variable因为由于硬编码的使用std::condition_variable::wait(std::unique_lock<std::mutex>&)而不承认我.fast_recursive_mutexstd::mutex
所以我的问题是:
wait()承认另一种互斥类型std::mutex呢?条件变量应该具有相对于的单个顺序notify()和unlock_sleep()(wait()在互斥锁被解锁并且线程作为一个原子操作序列休眠的操作中使用的虚函数调用)操作.要使用任意可锁定实现此功能,std::condition_variable_any通常在内部使用另一个互斥锁(以确保原子性和睡眠状态)
如果内部unlock_sleep()和notify()(notify_one()或notify_all())操作相对于彼此不是原子操作,则冒着线程解锁互斥锁的风险,另一个线程发出信号,然后原始线程将进入休眠状态并且从不唤醒.
我正在阅读std :: condition_variable_any的libstdc ++和libc ++实现,并注意到libc ++实现中的这段代码
{lock_guard<mutex> __lx(*__mut_);}
__cv_.notify_one();
Run Code Online (Sandbox Code Playgroud)
内部互斥锁被锁定,然后在信号操作之前立即解锁.这不是我上面描述的问题吗?
当使用timed_wait在boost::condition_variable具有持续时间,将等待状态超时即使用户(或NTP)更改系统时间的持续时间后?
例如,
boost::posix_time::time_duration wait_duration(0, 0, 1, 0); // 1 sec
// ** System time jumps back 15 minutes here. **
if( !signal.timed_wait(lock, wait_duration) )
{
// Does this condition happen 1 second later, or about 15 minutes later?
}
Run Code Online (Sandbox Code Playgroud) 我正在使用a SynchronisedQueue来进行线程之间的通信.我发现当附加线程在条件变量上等待时销毁线程对象会导致程序崩溃.这可以通过detach()在线程销毁之前调用来纠正.但我想知道等待条件变量的线程终止后会发生什么.有没有其他方法可以使用条件变量来避免这种情况?
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
template <typename Type> class SynchronisedQueue {
public:
void Enqueue(Type const & data) {
std::unique_lock<std::mutex> lock(mutex_);
queue_.push(data);
condition_.notify_one();
}
Type Dequeue() {
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.empty())
condition_.wait(lock);
Type result = queue_.front();
queue_.pop();
return result;
}
private:
std::queue<Type> queue_;
std::mutex mutex_;
std::condition_variable condition_;
};
class Worker {
public:
Worker(SynchronisedQueue<int> * queue) : queue_(queue) {}
void operator()() {
queue_->Dequeue(); // <-- The thread waits here.
}
private:
SynchronisedQueue<int> * queue_; …Run Code Online (Sandbox Code Playgroud) 我目前正在研究一个模拟扩展的Producer-Worker模型的问题.在这个问题中,有3个工人和3个工具可供使用,而对于工人来说,他们需要2个工具(和材料,但那些是无关紧要的).如果保险库中有> = 2个工具,则工作人员将采用2.否则,他们将等待条件变量,当> = 2时将发出信号.
对于2名工人来说这很好:一个工作然后将工具返回到金库,另一个等待工人将被唤醒并使用2个工具.问题是,有3名工人,总会有一个人渴望得到这些工具.
经过一些测试后,我注意到等待条件变量的线程以堆栈形式构建.有没有可能使它排队?(1等待,2等待,3等待.当1被唤醒并想要制造另一个时,他必须在2和3后面等待.)
这是一个示例输出.代码太长,所以如果真的有必要,我会发布它.有3个工作线程和1个工具互斥锁.任何挨饿的人都不同于其他人.
1 Tools taken. Remaining: 1
2 Waiting on tools...
3 Waiting on tools...
1 Operator Product made. Tools returned. Tools now:3
3 Tools taken. Remaining: 1
1 Waiting on tools...
3 Materials returned for switch.
3 Operator Product made. Tools returned. Tools now:3
1 Tools taken. Remaining: 1
3 Waiting on tools...
1 Materials returned for switch.
1 Operator Product made. Tools returned. Tools now:3
3 Tools taken. Remaining: 1
1 Waiting …Run Code Online (Sandbox Code Playgroud) 打算修改变量的线程必须
- 获取std :: mutex(通常通过std :: lock_guard)
- 在锁定时执行修改
- 在std :: condition_variable上执行notify_one或notify_all(不需要保持锁定以进行通知)
即使共享变量是原子的,也必须在互斥锁下对其进行修改,以便将修改正确地发布到等待的线程.
我不太明白,为什么修改原子变量需要锁定.请参阅以下代码段:
static std::atomic_bool s_run {true};
static std::atomic_bool s_hasEvent {false};
static std::mutex s_mtx;
static std::condition_variabel s_cv;
// Thread A - the consumer thread
function threadA()
{
while (s_run)
{
{
std::unique_lock<std::mutex> lock(s_mtx);
s_cv.wait(lock, [this]{
return m_hasEvents.load(std::memory_order_relaxed);
});
}
// process event
event = lockfree_queue.pop();
..... code to process the event ....
}
}
// Thread B - publisher thread
function PushEvent(event)
{
lockfree_queque.push(event)
s_hasEvent.store(true, std::memory_order_release);
s_cv.notify_one();
} …Run Code Online (Sandbox Code Playgroud) 线程之间的信号可以通过 std::promise/future 或良好的旧条件变量来实现,有人可以提供示例/用例,其中 1 比其他的更好吗?
我知道 CV 可用于在线程之间多次发出信号,您能否举例说明 std::future/promise 多次发出信号?
std::future::wait_for 的性能也与 std::condition_variable::wait 相同吗?假设我需要作为消费者在队列中等待多个期货,检查每个期货并检查它们是否像下面一样准备好是否有意义?
for(auto it = activeFutures.begin(); it!= activeFutures.end();) {
if(it->valid() && it->wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {
Printer::print(std::string("+++ Value " + std::to_string(it->get()->getBalance())));
activeFutures.erase(it);
} else {
++it;
}
}
Run Code Online (Sandbox Code Playgroud) 我有以下代码,注释行上的死锁.基本上f1和f2作为程序中的单个线程运行.f1期望i为1并递减它,通知cv.f2期望i为0并递增它,通知cv.我假设如果f2将i增加到1,则调用死锁,调用cv.notify(),然后f1读取过时的i值(为0),因为互斥锁和i之间没有内存同步,然后等待并且永远不会被唤醒起来.然后f2也进入睡眠状态,现在两个线程都在等待一个永远不会被通知的cv.
如何编写此代码以便不会发生死锁?基本上我想要实现的是拥有一些由两个线程更新的原子状态.如果其中一个线程的状态不正确,我不想旋转; 相反,我想使用cv功能(或类似的东西)在值正确时唤醒线程.
我使用g ++ - 7用O3编译代码(尽管在O0和O3中都发生了死锁).
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
std::atomic_size_t i{0};
std::mutex mut;
std::condition_variable cv;
void f1() {
while (1) {
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, []() { return i.load() > 0; }); // deadlocks
}
--i;
cv.notify_one();
std::cout << "i = " << i << std::endl; // Only to avoid optimization
}
}
void f2() {
while (1) {
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, []() { return i.load() < 1; }); // deadlocks …Run Code Online (Sandbox Code Playgroud) 查看几个视频和文档示例,我们在调用notify_all(). 之后调用会更好吗?
常见的方式:
通知程序线程内部:
//prepare data for several worker-threads;
//and now, awaken the threads:
std::unique_lock<std::mutex> lock2(sharedMutex);
_threadsCanAwaken = true;
lock2.unlock();
_conditionVar.notify_all(); //awaken all the worker threads;
//wait until all threads completed;
//cleanup:
_threadsCanAwaken = false;
//prepare new batches once again, etc, etc
Run Code Online (Sandbox Code Playgroud)
在工作线程之一内部:
while(true){
// wait for the next batch:
std::unique_lock<std::mutex> lock1(sharedMutex);
_conditionVar.wait(lock1, [](){return _threadsCanAwaken});
lock1.unlock(); //let sibling worker-threads work on their part as well
//perform the final task
//signal …Run Code Online (Sandbox Code Playgroud) 我目前正在研究Google的细丝工作系统。您可以在此处找到源代码。令我困惑的部分是这个requestExit()方法:
void JobSystem::requestExit() noexcept {
mExitRequested.store(true);
{ std::lock_guard<Mutex> lock(mLooperLock); }
mLooperCondition.notify_all();
{ std::lock_guard<Mutex> lock(mWaiterLock); }
mWaiterCondition.notify_all();
}
Run Code Online (Sandbox Code Playgroud)
我很困惑,为什么即使在锁定和解锁之间没有任何动作,也需要锁定和解锁。在任何情况下都需要这种空的锁定和解锁吗?