[英]C++ multithreading stopping threads using concurrent variable
尝试使用for循环创建一个简单的多线程示例。 我试图让它们在块中循环,如下所示:
Thread 1 printing 0
Thread 2 printing 0
Thread 3 printing 0
Thread 4 printing 0
Thread 1 printing 1
Thread 2 printing 1
Thread 3 printing 1
Thread 4 printing 1
这意味着:他们都打印“1”,然后他们都等待大家都这样做,然后他们都打印“2”,再次等待所有人,打印“3”等。
所以我写了这段代码:
#include <iostream>
#include <thread>
#include <string.h>
using namespace std;
bool flags[4] = {true,true,true,true};
bool checkAll(){
bool res = false;
for(int i=0;i<4;i++){
res = res|flags[i];
}
return res;
}
void printer(int id){
for(int i=0;i<100;i++){
flags[id] = true;
cout << "Thread: " << id << " printing " << i << endl;
flags[id] = false;
while(checkAll()) {}
}
}
int main(int argc, char *argv[]){
thread t1(printer,0);
thread t2(printer,1);
thread t3(printer,2);
thread t4(printer,3);
t4.join();
t3.join();
t2.join();
t1.join();
return 0;
}
但它没有按预期工作。 据我所知,由于并发问题(几个线程读/写同一个变量),它不起作用。
所以,我尝试使用条件变量来解决它:
#include <iostream>
#include <thread>
#include <string.h>
#include <mutex>
#include <condition_variable>
using namespace std;
bool flags[4] = {true,true,true,true};
mutex m;
condition_variable g_queuecheck;
bool done = false;
bool checkAll(){
bool res = false;
for(int i=0;i<4;i++){
res = res|flags[i];
}
return res;
}
void printer(int id){
unique_lock<mutex> locker(m);
for(int i=0;i<100;i++){
flags[id] = true;
cout << "Thread: " << id << " printing " << i << endl;
flags[id] = false;
g_queuecheck.wait(locker);
}
}
void controller(){
while(!done){
if(!checkAll()){
g_queuecheck.notify_all();
}
}
}
int main(int argc, char *argv[]){
thread t0(controller);
thread t1(printer,0);
thread t2(printer,1);
thread t3(printer,2);
thread t4(printer,3);
t4.join();
t3.join();
t2.join();
t1.join();
done = true;
t0.join();
return 0;
}
但也不起作用。 所以,这里有我的问题:是否有可能像第一个代码一样简单地做到这一点? 如果没有,我在第二个做错了什么? 非常感谢。
您的示例不起作用,因为更新和检查flags数组存在竞争条件。
看起来像你想要的虽然是一个众所周知的原始称为障碍 。 例如,这可以使用信号量来实现。 有关其工作原理的详细信息,请参见The Semaphores小册子第3.6节。
有了屏障,您的代码可以简洁地编写为:
const int nThreads = 4;
const int nIter = 100;
mutex m;
barrier barrier(nThreads);
void printer(int id) {
for (int i = 0; i < nIter; i++) {
{
lock_guard<mutex> lock(m); // lock to prevent interleaved console output
cout << "Thread: " << id << " printing " << i << endl;
}
barrier.wait();
}
}
int main(int argc, char **argv) {
vector<thread> ts;
for (int i = 0; i < nThreads; i++) {
ts.emplace_back(thread(printer, i));
}
for (int i = 0; i < nThreads; i++) {
ts[i].join();
}
return 0;
}
下面是一个简单的信号量实现(从这里复制)。
class semaphore {
private:
mutex mtx;
condition_variable cv;
int count;
public:
semaphore(int count_ = 0):count(count_){;}
void notify()
{
unique_lock<mutex> lck(mtx);
++count;
cv.notify_one();
}
void wait()
{
unique_lock<mutex> lck(mtx);
while(count == 0){
cv.wait(lck);
}
count--;
}
};
使用它,您可以在引用的书中实现屏障:
class barrier {
public:
barrier(int n): n(n), count(0) {}
void wait() {
phase1();
phase2();
}
private:
mutex m;
semaphore turnstile1, turnstile2;
int n, count;
void phase1() {
m.lock();
count++;
if (count == n) {
for (int i = 0; i < n; i++)
turnstile1.notify();
}
m.unlock();
turnstile1.wait();
}
void phase2() {
m.lock();
count--;
if (count == 0) {
for (int i = 0; i < n; i++)
turnstile2.notify();
}
m.unlock();
turnstile2.wait();
}
};
嗯,这可以做你想要的。 它工作没有atomic
但我想到了什么,无论如何扔它。 :)
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <atomic>
const size_t num_threads = 10;
const size_t num_reps = 10;
std::mutex m;
std::atomic_int pos;
void printer(int id)
{
for(int i = 0; i < num_reps; ++i)
{
std::unique_lock<std::mutex> l(m);
if(pos.load() == id)
{
std::cout << "Thread: " << id << " printing " << i << std::endl;
pos.exchange((pos.load() + 1) % num_threads);
}
}
}
int main()
{
m.lock();
pos.store(0);
std::vector<std::thread> v;
for(int i = 0; i < num_threads; ++i)
{
v.emplace_back(std::thread(printer, i));
}
m.unlock();
bool done;
do
{
done = true;
for(int i = 0; i < num_threads; ++i)
{
if(v[i].joinable())
{
done = false;
v[i].join();
}
}
}
while(!done);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.