【问题标题】:synchronization issue with 3 threads and 2 shared resources in c++11c++11中3个线程和2个共享资源的同步问题
【发布时间】:2014-02-19 00:44:47
【问题描述】:

我有 3 个线程和 2 个共享资源,需要一些锁定...我试图用 2 个缓冲区来说明资源... - 线程 1 只能访问资源 1 - 线程 2 可以访问资源 1 和 2 - 线程 3 可以访问资源 1 和 2

谁能告诉我为什么以下锁定失败?因为thread2和thread3将访问资源1和2...我想我可以使用try_lock? ...似乎问题出现了,当 thread2 和 thread3 一次只能锁定 1 个互斥锁时...有什么想法吗?

#include <iostream> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 
#include <vector> 
#include <algorithm> 
#include <cassert> 
using namespace std; 

class SynchronizationTest { 
private: 
    mutex lock_r1; 
    mutex lock_r2; 
    vector<pair<string, int>> buffer_r1; 
    vector<pair<string, int>> buffer_r2; 
    unsigned int buffer_r1_max_size; 
    unsigned int buffer_r2_max_size; 

    bool buffer_r1_inc_element(const string &thread_id) {       
        if (buffer_r1.size() == buffer_r1_max_size) { 
            return true; 
        } 

        if (buffer_r1.size() == 0) { 
            buffer_r1.push_back(make_pair(thread_id, 0)); 
        } 
        else { 
            int last_val = buffer_r1.back().second; 
            buffer_r1.push_back(make_pair(thread_id, ++last_val)); 
        } 

        return false; 
    } 

    bool buffer_r2_inc_element(const string &thread_id) {   
        if (buffer_r2.size() == buffer_r2_max_size) { 
            return true; 
        } 

        if (buffer_r2.size() == 0) { 
            buffer_r2.push_back(make_pair(thread_id, 0)); 
        } 
        else { 
            int last_val = buffer_r2.back().second; 
            buffer_r2.push_back(make_pair(thread_id, ++last_val)); 
        } 

        return false; 
    } 

public: 
    SynchronizationTest(int buff_r1_size, int buff_r2_size) : buffer_r1_max_size(buff_r1_size), 
                                                              buffer_r2_max_size(buff_r2_size) {} 

    void thread1() { 
        bool buffer_r1_full = false; 

        while (!buffer_r1_full) { 
            { 
                unique_lock<mutex> l(lock_r1, std::defer_lock); 
                if (l.try_lock()) { 
                    buffer_r1_full = buffer_r1_inc_element("thread1"); 
                } 
            } 

            std::this_thread::sleep_for(std::chrono::milliseconds(10)); 
        } 
    } 

    void thread2() { 
        bool buffer_r1_full = false; 
        bool buffer_r2_full = false; 

        while (!buffer_r1_full || !buffer_r2_full) { 
            { 
                unique_lock<mutex> lock1(lock_r1, defer_lock); 
                unique_lock<mutex> lock2(lock_r2, defer_lock); 

                int result = try_lock(lock1, lock2); 
                if(result == -1) { 
                    buffer_r1_full = buffer_r1_inc_element("thread2"); 
                    buffer_r2_full = buffer_r2_inc_element("thread2"); 
                } 
                else if(result != 0) { 
                    buffer_r1_full = buffer_r1_inc_element("thread2"); 
                } 
                else if(result != 1) { 
                    buffer_r2_full = buffer_r2_inc_element("thread2"); 
                } 
            } 

            std::this_thread::sleep_for(std::chrono::milliseconds(10)); 
        } 
    } 

    void thread3() { 
        bool buffer_r1_full = false; 
        bool buffer_r2_full = false; 

        while (!buffer_r1_full || !buffer_r2_full) { 
            { 
                unique_lock<mutex> lock1(lock_r1, defer_lock); 
                unique_lock<mutex> lock2(lock_r2, defer_lock); 

                int result = try_lock(lock1, lock2); 
                if(result == -1) { 
                    buffer_r1_full = buffer_r1_inc_element("thread3"); 
                    buffer_r2_full = buffer_r2_inc_element("thread3"); 
                } 
                else if(result != 0) { 
                    buffer_r1_full = buffer_r1_inc_element("thread3"); 
                } 
                else if(result != 1) { 
                    buffer_r2_full = buffer_r2_inc_element("thread3"); 
                } 
            } 

            std::this_thread::sleep_for(std::chrono::milliseconds(10)); 
        } 
    } 

    void print_buffer() { 
        for_each(buffer_r1.begin(), buffer_r1.end(), [](pair<string, int> p) { cout << p.first.c_str() << " " << p.second << endl; }); 
        cout << '\n'; 
        for_each(buffer_r2.begin(), buffer_r2.end(), [](pair<string, int> p) { cout << p.first.c_str() << " " << p.second << endl; }); 
    } 
}; 

int main() { 
    // your code goes here 
    SynchronizationTest st(20, 20); 

    thread t1(&SynchronizationTest::thread1, &st); 
    thread t2(&SynchronizationTest::thread2, &st); 
    thread t3(&SynchronizationTest::thread3, &st); 

    t1.join(); 
    t2.join(); 
    t3.join(); 

    st.print_buffer(); 

    return 0; 
}

【问题讨论】:

    标签: c++ multithreading c++11 mutex deadlock


    【解决方案1】:

    std::try_lock 不能那样工作。如果它返回 -1,则持有所有锁。如果它返回一个非负整数,则不持有任何锁。返回值告诉哪个锁失败了,但是任何被成功锁定的锁都会在try_lock 返回之前被释放。

    【讨论】:

    • 如果返回不是-1,怎么知道哪个锁成功了? -1 表示可以获取两个锁...?
    • @Gerald try_lock(如lock)尝试以无死锁的方式获取您传递给它的所有锁。如果try_lock 返回-1,则将它们全部锁定。如果它返回一个非负整数N,它在try_lock 第一个N 参数失败之前获取了第一个N 参数,然后在返回之前释放了第一个N 参数。是不是更清楚了?
    【解决方案2】:

    问题解决了:

    unique_lock<mutex> lock1(lock_r1, defer_lock);
    unique_lock<mutex> lock2(lock_r2, defer_lock);
    
    bool result1 = lock1.try_lock();
    bool result2 = lock2.try_lock();
    
    if(result1 && result2) {
        buffer_r1_full = buffer_r1_inc_element("thread2");
        buffer_r2_full = buffer_r2_inc_element("thread2");
    }
    else if(result1) { 
        buffer_r1_full = buffer_r1_inc_element("thread2");
    }
    else if(result2) { 
        buffer_r2_full = buffer_r2_inc_element("thread2");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多