2017-08-28 93 views
1

这里的例子只是想保护iData以确保只有一个线程同时访问它。一个互斥对比多个互斥。哪一个更适合线程池?

struct myData; 
myData iData; 

方法1,调用函数中的互斥体(可以创建多个互斥锁):

void _proceedTest(myData &data) 
    { 
     std::mutex mtx; 
     std::unique_lock<std::mutex> lk(mtx); 
     modifyData(data); 
     lk.unlock; 
    } 

    int const nMaxThreads = std::thread::hardware_concurrency(); 
    vector<std::thread> threads; 
    for (int iThread = 0; iThread < nMaxThreads; ++iThread) 
    { 
     threads.push_back(std::thread(_proceedTest, iData)); 
    } 

    for (auto& th : threads) th.join(); 

方法二,只用一个互斥体:

void _proceedTest(myData &data, std::mutex &mtx) 
    { 
     std::unique_lock<std::mutex> lk(mtx); 
     modifyData(data); 
     lk.unlock; 
    } 
    std::mutex mtx; 
    int const nMaxThreads = std::thread::hardware_concurrency(); 
    vector<std::thread> threads; 
    for (int iThread = 0; iThread < nMaxThreads; ++iThread) 
    { 
     threads.push_back(std::thread(_proceedTest, iData, mtx)); 
    } 

    for (auto& th : threads) th.join(); 
  1. 我要打确保方法1(多重互斥锁)确保只有一个线程可以同时访问iData。
  2. 如果方法1是正确的,不确定方法1比方法2更好吗? 谢谢!
+0

您的意思是方法1并不保证iData仅被一个线程访问? – lightrek

+0

它应该如何在不同线程之间共享'std :: mutex'? – user0042

回答

3
  1. 我想确保的方法1(多个互斥锁),确保只有一个线程可以在同一时间访问IDATA。

你的第一个例子在堆栈上创建一个本地互斥变量,它不会与其他线程共享。因此它完全没用。
它不保证独家访问iData

  • 如果方法1是正确的,不能确定方法1是方法2的更好?
  • 这是不正确的。

    +0

    刚刚注意到方法2也不正确。应使用std :: ref来包装iData和mtx – lightrek

    +1

    @lightrek您可能需要['std :: ref()'](http://en.cppreference.com/w/cpp/utility/functional/ref)让它正常工作。 – user0042

    0

    当您离开_proceedTest范围时,版本1中的互斥锁将超出范围,因此锁定互斥锁是没有意义的,因为它不会被其他线程访问。

    在第二个版本中,多个线程可以共享互斥锁(只要它不超出范围,例如作为类成员),这样一个线程可以锁定它,另一个线程可以看到它被锁定(并且将不能锁定它,因此术语互斥)。

    2

    方法1仅适用于互斥变量为static的情况。

    void _proceedTest(myData &data) 
    { 
        static std::mutex mtx; 
        std::unique_lock<std::mutex> lk(mtx); 
        modifyData(data); 
        lk.unlock; 
    } 
    

    这将使mtx通过输入_proceedTest所有线程共享。

    由于static函数范围变量只对该函数的用户可见,所以对于传入的data而言,它并不是一个足够的锁。这是因为可以想象,多个线程可能会调用每个想要操作的不同函数data。因此,尽管方法1是可挽救的,但即使锁与数据之间的内聚力较弱,方法2仍然更好。

    2

    其他答案在技术层面上是正确的,但有一个重要的语言无关的东西缺失:你总是更喜欢减少不同互斥/锁的数量/ ...!

    因为:只要你有一个以上一个件事,一个线程需要获取为了做一些事情(来然后释放所有获取的锁)为了变得至关重要。

    当你有2把锁,你必须在不同的代码块,如:

    getLockA() { 
        getLockB() { 
        do something 
        release B 
    release A 
    

    而且

    getLockB() { 
        getLockA() { 
    

    就可以快速运行到死锁 - 因为两个线程/进程每个人可以获得一个锁 - 然后他们都被卡住了,等待另一个释放锁。当然 - 当看到上面的例子时,“你永远不会犯错,并且总是先选A然后B”。但是如果这些锁存在于应用程序的完全不同的部分呢?而且它们不是以相同的方法或类来获得的,而是在说3,5个嵌套方法调用过程中获得的?

    因此:当你可以解决你的问题与一个锁 - 使用一个只锁!你需要做的事情越多,死锁的风险就越高。