使用原子变量同步更多线程

时间:2015-12-05 01:18:52

标签: c++ multithreading mutex atomic locks

我现在正在进行学校投影,我在同步3个线程(2个线程+ mian线程)方面遇到了一些问题。描述说我必须打印100x" ping"那么100x" pong"和100x" \ n",但按此顺序:

PingPong \ n等等......

当我启动我的代码时就像我现在一样它只打印100xPing然后100xPong然后100x \ n输出,我不明白为什么:(

我无法理解的一点是,当我将counter设置为1时它应该停止并且它应该打开cond.wait();之后,它会转移到pong()等等......

以下是代码:

  #include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <atomic>
using namespace std;
mutex m; // Mutex
         // Bedingungsvariable
condition_variable cond;
atomic<int> counter = 0;
bool done= true;

void ping() {
    unique_lock <mutex > lock{ m }; // m sperren

        while (counter != 0) {
            cond.wait(lock); //sperren und dann wieder freigeben
        }

    while (counter == 0) {

        for (int i = 0; i < 100; i++) {
            cout << "Ping"; 
            counter = 1;
            cond.notify_one();

        }   

    }
}
void pong() {
    unique_lock <mutex > lock{ m }; // m sperren
    while (counter != 1) {
        cond.wait(lock);
    }
    while (counter == 1) {

        for (int i = 0; i < 100; i++) {
            cout << "Pong";
            counter = 2;
            cond.notify_one();          

        }

    }

}


int main() {
    thread t1(pong);
    thread t(ping); // Zweiten Thread starten
    unique_lock <mutex > lock{ m }; // m sperren
    while (counter != 2) cond.wait(lock);
    while (counter == 2) {

        for (int i = 0; i < 100; i++) {
            cout << "\n";
            counter = 0;
            cond.notify_one();

        }       
    }
    lock.unlock(); // Mutex freigeben
    t.join();
    t1.join();
    system("PAUSE");
    return EXIT_SUCCESS;
}

1 个答案:

答案 0 :(得分:1)

我花时间纠正并提供反馈。请花时间学习和理解。我还在代码中添加了注释。

  • 我删除了行#include <string>,因为此程序中没有使用string
  • 我删除了行bool done = true;。我认为你不需要它。
  • 如果您想使用条件变量(Bedingungsvariablen),则必须#include <condition_variable>
  • atomic<int> counter = 0;给了我一个错误(g ++ 4.8.4,Ubuntu,C ++ 11标志)。相反,我将该行替换为atomic<int> counter{0};
  • 关于线程同步,我在代码中添加了注释。请检查一下。 cond.wait(*lock*, *lambda*);可能看起来很奇怪,但它与您的while(*condition*) cond.wait(*lock*);相同。
  • notify_one()只通知一个帖子,但你无法控制哪一个被唤醒。因此(因为你有两个以上的线程)我使用notify_all()
  • 我删除了行system("PAUSE")。不需要。

摘要(同步机制):

基本上每个计数器值(0,1,2)对应一个线程(我认为你有这个想法)。
但是,您跳过while循环,因为您只想循环/处理一百次;你只需要循环一百次 因此,同步最好放入相应的for循环中,并且所有循环都遵循相同的模式:

  1. 获取锁定,释放互斥锁并等待条件为真。同时线程被阻止。
  2. 处理数据并设置计数器(另一个线程的条件)。
  3. 解锁互斥锁并通知所有等待的线程(以便可以唤醒符合条件的下一个线程)。
  4. 所以线程可以依次执行。

    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <atomic>
    #include <condition_variable>
    
    using namespace std;
    
    mutex m;                 // Mutex
    condition_variable cond; // Bedingungsvariable
    atomic<int> counter{0};
    
    void ping() {
    
        for (int i = 0; i < 100; i++) {
    
            //cout << "Ping: m sperren und warten" << endl;
            // m sperren und ...
            unique_lock <mutex > lock{m};
            //... dann wieder freigeben
            //sobald counter == 0 gilt
            cond.wait(lock, [] {
                return counter == 0;
            });
    
            //Datenverarbeitung und ...
            //... counter setzen für nächsten Thread
            cout << "Ping";
            counter = 1;
    
            //cout << "Ping: m freigeben und benachrichtigen" << endl;
            //m freigeben und
            //andere Threads benachrichtigen
            lock.unlock();
            cond.notify_all();
    
        }
    }
    
    void pong() {
    
        for (int i = 0; i < 100; i++) {
    
            //cout << "Pong: m sperren und warten" << endl;
            //m sperren und ...
            unique_lock <mutex > lock{m};
            //... dann wieder freigeben
            //sobald counter == 1 gilt
            cond.wait(lock, [] {
                return counter == 1;
            });
    
            //Datenverarbeitung und ...
            //... counter setzen für nächsten Thread
            cout << "Pong";
            counter = 2;
    
            //cout << "Pong: m freigeben und benachrichtigen" << endl;
            //m freigeben und
            //andere Threads benachrichtigen
            lock.unlock();
            cond.notify_all();
        }
    
    }
    
    int main() {
    
        thread t(ping); // ping Thread starten
        thread t1(pong); // pong Thread starten
    
        for (int i = 0; i < 100; i++) {
    
            //cout << "\\n: m sperren und warten" << endl;
            // m sperren und ...
            unique_lock <mutex > lock{m};
            //... dann wieder freigeben
            //sobald counter == 2 gilt
            cond.wait(lock, [] {
                return counter == 2;
            });
    
            //Datenverarbeitung und ...
            //... counter setzen für nächsten Thread
            cout << endl;
            counter = 0;
    
            //cout << "\\n: m freigeben und benachrichtigen" << endl;
            //m freigeben und
            //andere Threads benachrichtigen
            lock.unlock();
            cond.notify_all();
    
        }
    
        t.join();
        t1.join();
    
        return EXIT_SUCCESS;
    }
    

    注1:

    这不起作用:

    atomic<int> counter = 0;
    

    这有效:

    atomic<int> counter(0);
    

    atomic<int> counter{0};
    

    atomic<int> counter;
    ...
    counter = 0;