繁体   English   中英

C ++多线程使用并发变量停止线程

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM