Windows C++ 中的同步
Synchronization in Windows C++
我需要实现如下系统:1写者和3读者互斥,但3读者可以同时读。作者在一个名为 dato 的共享变量上写入一个随机数,读者必须将其打印到控制台。预期的输出是:
我写道:7;我读到:7;我读到:7;我读:7
我写道:1;我读: 1 ;我读: 1 ;我读过:1
我写道:9;我读到:9;我读到:9;我读到:9
我在互斥体 m 上使用了两个 unique_lock,还有两个 condition_variables:cv1 用于读者(只有当写入者已经写入时他们才能读取)和 cv2 用于写入者(它可以只写入如果所有读者都阅读过)。
为了保证并行读取,wait之后我解锁了,我在cout指令之后拿了锁。我认为作者无法锁定,因为当他们正在阅读时,他正在等待,并且条件 opDone == 3 无效。
相反,输出是:
我写道:1
我读过:1
我读了: 我读了: 1
我读过:1
我读过:1
1
这是代码:
// nreader1writer.cpp : Defines the entry point for the console application.
#include "stdafx.h"
condition_variable cv1, cv2;
mutex m;
volatile atomic_int opDone = 0;
volatile atomic_bool iWrote = false;
volatile atomic_bool flag = false;
volatile atomic_int dato;
void writer();
void reader();
int _tmain()
{
thread t1(reader);
thread t2(reader);
thread t3(reader);
thread t4(writer);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
void writer() {
unique_lock <mutex> ulw (m, defer_lock);
while (opDone.load() != 3); //In this way, writer starts just when all readers are already waiting
ulw.lock();
opDone.store(0);
iWrote.store(false);
while (1) {
dato.store( (int) rand()%10);
cout << "I wrote: " << dato.load() << endl;
iWrote.store(true);
cv1.notify_all();
cv2.wait(ulw, []() {
return (opDone.load() == 3);
});
opDone.store(0);
iWrote.store(false);
}
}
void reader() {
unique_lock <mutex> ulr (m, defer_lock);
ulr.lock();
opDone.fetch_add(1);
while (1) {
cv1.wait(ulr, []() {
return (iWrote.load() == true && opDone.load() < 3);
});
ulr.unlock();
cout << "I read: " << dato << endl;
ulr.lock();
opDone.fetch_add(1);
cv2.notify_one();
}
}
代码完美运行如果我在读取之前不解锁(),但是这样读取操作不是并行的。有什么建议吗?
看看你的原子变量的初始化。例如,Clang 会发出警告。
volatile atomic_int opDone = 0;
// error: copying variable of type 'atomic_int' (aka '__atomic_base') invokes deleted constructor
工作草案(当前 N4527)在 §8.5.15 中说了以下内容。
The initialization that occurs in the = form of a
brace-or-equal-initializer or condition (6.4), as well as in argument
passing, function return, throwing an exception (15.1), handling an
exception (15.3), and aggregate member initialization (8.5.1), is
called copy-initialization. [ Note: Copy-initialization may invoke a
move (12.8). — end note ]
原因是你不能复制原子。所有加载和存储都必须通过显式调用进行。修复以下方法应该可以解决问题:
static atomic_int opDone(0);
我需要实现如下系统:1写者和3读者互斥,但3读者可以同时读。作者在一个名为 dato 的共享变量上写入一个随机数,读者必须将其打印到控制台。预期的输出是: 我写道:7;我读到:7;我读到:7;我读:7 我写道:1;我读: 1 ;我读: 1 ;我读过:1 我写道:9;我读到:9;我读到:9;我读到:9
我在互斥体 m 上使用了两个 unique_lock,还有两个 condition_variables:cv1 用于读者(只有当写入者已经写入时他们才能读取)和 cv2 用于写入者(它可以只写入如果所有读者都阅读过)。
为了保证并行读取,wait之后我解锁了,我在cout指令之后拿了锁。我认为作者无法锁定,因为当他们正在阅读时,他正在等待,并且条件 opDone == 3 无效。
相反,输出是: 我写道:1 我读过:1 我读了: 我读了: 1 我读过:1 我读过:1 1
这是代码:
// nreader1writer.cpp : Defines the entry point for the console application.
#include "stdafx.h"
condition_variable cv1, cv2;
mutex m;
volatile atomic_int opDone = 0;
volatile atomic_bool iWrote = false;
volatile atomic_bool flag = false;
volatile atomic_int dato;
void writer();
void reader();
int _tmain()
{
thread t1(reader);
thread t2(reader);
thread t3(reader);
thread t4(writer);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
void writer() {
unique_lock <mutex> ulw (m, defer_lock);
while (opDone.load() != 3); //In this way, writer starts just when all readers are already waiting
ulw.lock();
opDone.store(0);
iWrote.store(false);
while (1) {
dato.store( (int) rand()%10);
cout << "I wrote: " << dato.load() << endl;
iWrote.store(true);
cv1.notify_all();
cv2.wait(ulw, []() {
return (opDone.load() == 3);
});
opDone.store(0);
iWrote.store(false);
}
}
void reader() {
unique_lock <mutex> ulr (m, defer_lock);
ulr.lock();
opDone.fetch_add(1);
while (1) {
cv1.wait(ulr, []() {
return (iWrote.load() == true && opDone.load() < 3);
});
ulr.unlock();
cout << "I read: " << dato << endl;
ulr.lock();
opDone.fetch_add(1);
cv2.notify_one();
}
}
代码完美运行如果我在读取之前不解锁(),但是这样读取操作不是并行的。有什么建议吗?
看看你的原子变量的初始化。例如,Clang 会发出警告。
volatile atomic_int opDone = 0;
// error: copying variable of type 'atomic_int' (aka '__atomic_base') invokes deleted constructor
工作草案(当前 N4527)在 §8.5.15 中说了以下内容。
The initialization that occurs in the = form of a brace-or-equal-initializer or condition (6.4), as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1), is called copy-initialization. [ Note: Copy-initialization may invoke a move (12.8). — end note ]
原因是你不能复制原子。所有加载和存储都必须通过显式调用进行。修复以下方法应该可以解决问题:
static atomic_int opDone(0);