Edw*_*ard 6 c++ multithreading condition-variable c++11 visual-studio-2012
我无法使代码在一个简单的VS2012控制台应用程序中可靠地运行,该应用程序由使用C++ 11条件变量的生产者和使用者组成.我的目标是生成一个小的可靠程序(用作更复杂程序的基础),它使用3参数wait_for方法或者我在这些网站上收集的代码中的wait_until方法:
condition_variable: wait_for, wait_until
我想使用3参数wait_for和下面的谓词,除非它需要使用类成员变量对我以后最有用.我只在运行一分钟后收到"访问冲突写入位置0x_ _ "或"无效参数已传递给服务或功能"作为错误.
steady_clock和2参数wait_until是否足以替换3参数wait_for?我也试过这个没有成功.
有人可以展示如何使用下面的代码无限期地运行,没有错误或奇怪的行为,从夏令时或互联网时间同步的挂钟时间的变化?
链接到可靠的示例代码可能同样有用.
// ConditionVariable.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
#include <queue>
#include <chrono>
#include <atomic>
#define TEST1
std::atomic<int>
//int
qcount = 0; //= ATOMIC_VAR_INIT(0);
int _tmain(int argc, _TCHAR* argv[])
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool notified = false;
unsigned int count = 0;
std::thread producer([&]() {
int i = 0;
while (1) {
std::this_thread::sleep_for(std::chrono::microseconds(1500));
std::unique_lock<std::mutex> lock(m);
produced_nums.push(i);
notified = true;
qcount = produced_nums.size();
cond_var.notify_one();
i++;
}
cond_var.notify_one();
});
std::thread consumer([&]() {
std::unique_lock<std::mutex> lock(m);
while (1) {
#ifdef TEST1
// Version 1
if (cond_var.wait_for(
lock,
std::chrono::microseconds(1000),
[&]()->bool { return qcount != 0; }))
{
if ((count++ % 1000) == 0)
std::cout << "consuming " << produced_nums.front () << '\n';
produced_nums.pop();
qcount = produced_nums.size();
notified = false;
}
#else
// Version 2
std::chrono::steady_clock::time_point timeout1 =
std::chrono::steady_clock::now() +
//std::chrono::system_clock::now() +
std::chrono::milliseconds(1);
while (qcount == 0)//(!notified)
{
if (cond_var.wait_until(lock, timeout1) == std::cv_status::timeout)
break;
}
if (qcount > 0)
{
if ((count++ % 1000) == 0)
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
qcount = produced_nums.size();
notified = false;
}
#endif
}
});
while (1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Visual Studio Desktop Express安装了1个重要更新,Windows Update没有其他重要更新.我正在使用Windows 7 32位.
遗憾的是,这实际上是VS2012实现condition_variable的一个错误,并且修补程序不会被修补.你必须在它发布时升级到VS2013.
看到:
http://connect.microsoft.com/VisualStudio/feedback/details/762560
首先,在使用condition_variable
s 时,我个人更喜欢一些包装类,例如AutoResetEvent
C# 中的:
struct AutoResetEvent
{
typedef std::unique_lock<std::mutex> Lock;
AutoResetEvent(bool state = false) :
state(state)
{ }
void Set()
{
auto lock = AcquireLock();
state = true;
variable.notify_one();
}
void Reset()
{
auto lock = AcquireLock();
state = false;
}
void Wait(Lock& lock)
{
variable.wait(lock, [this] () { return this->state; });
state = false;
}
void Wait()
{
auto lock = AcquireLock();
Wait(lock);
}
Lock AcquireLock()
{
return Lock(mutex);
}
private:
bool state;
std::condition_variable variable;
std::mutex mutex;
};
Run Code Online (Sandbox Code Playgroud)
这可能与 C# 类型的行为不同,或者可能没有应有的效率,但它可以为我完成工作。
其次,当我需要实现一种生产/消费习惯时,我尝试使用并发队列实现(例如tbb 队列)或自己编写一个。但您还应该考虑使用主动对象模式来纠正错误。但对于简单的解决方案,我们可以使用这个:
template<typename T>
struct ProductionQueue
{
ProductionQueue()
{ }
void Enqueue(const T& value)
{
{
auto lock = event.AcquireLock();
q.push(value);
}
event.Set();
}
std::size_t GetCount()
{
auto lock = event.AcquireLock();
return q.size();
}
T Dequeue()
{
auto lock = event.AcquireLock();
event.Wait(lock);
T value = q.front();
q.pop();
return value;
}
private:
AutoResetEvent event;
std::queue<T> q;
};
Run Code Online (Sandbox Code Playgroud)
这个类有一些异常安全问题,并且缺少方法的常量性,但就像我说的,对于一个简单的解决方案来说,这应该适合。
因此,修改后的代码如下所示:
int main(int argc, char* argv[])
{
ProductionQueue<int> produced_nums;
unsigned int count = 0;
std::thread producer([&]() {
int i = 0;
while (1) {
std::this_thread::sleep_for(std::chrono::microseconds(1500));
produced_nums.Enqueue(i);
qcount = produced_nums.GetCount();
i++;
}
});
std::thread consumer([&]() {
while (1) {
int item = produced_nums.Dequeue();
{
if ((count++ % 1000) == 0)
std::cout << "consuming " << item << '\n';
qcount = produced_nums.GetCount();
}
}
});
producer.join();
consumer.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3027 次 |
最近记录: |