跨线程的unique_lock?

时间:2013-09-21 20:59:26

标签: c++ c++11 concurrency locking

我在概念化unique_lock如何跨线程运行时遇到了一些麻烦。我试图快速举例来重新创建一些我通常使用condition_variable的东西。

#include <mutex>
#include <thread>
using namespace std;
mutex m;
unique_lock<mutex>* mLock;
void funcA()
{
    //thread 2
    mLock->lock();//blocks until unlock?Access violation reading location 0x0000000000000000.
}

int _tmain(int argc, _TCHAR* argv[])
{
    //thread 1
    mLock = new unique_lock<mutex>(m);
    mLock->release();//Allows .lock() to be taken by a different thread?
    auto a = std::thread(funcA);
    std::chrono::milliseconds dura(1000);//make sure thread is running
    std::this_thread::sleep_for(dura);
    mLock->unlock();//Unlocks thread 2's lock?
    a.join();
    return 0;
}

4 个答案:

答案 0 :(得分:9)

不应一次从多个线程访问

unique_lock。它不是以这种方式设计为线程安全的。相反,多个unique_lock s(局部变量)引用相同的全局mutex。只有mutex本身可以被多个线程同时访问。即便如此,我的陈述也排除了~mutex()

例如,有人知道多个线程可以访问mutex::lock(),因为它的规范包括以下内容:

  

同步:同一对象的先前unlock()操作应同步(4.7)此操作。

其中同步是4.7 [intro.multithread](及其子条款)中定义的术语。

答案 1 :(得分:4)

这看起来没有问题。首先,release是&#34;解除互斥锁的关联而不解锁它&#34;,这不太可能是你想在那个地方做的事情。它基本上意味着你的mutex中不再有unique_lock<mutex> - 这会使它变得毫无用处 - 而且可能是你获得违规行为的原因&#34;。

编辑:经过一些&#34;按摩&#34;你的代码,并说服g ++ 4.6.3做我想做的事情(因此#define _GLIBCXX_USE_NANOSLEEP),这是一个有效的例子:

#define _GLIBCXX_USE_NANOSLEEP
#include <chrono>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
mutex m;
void funcA()
{
    cout << "FuncA Before lock" << endl;
    unique_lock<mutex> mLock(m);
    //thread 2
    cout << "FuncA After lock" << endl;
    std::chrono::milliseconds dura(500);//make sure thread is running
    std::this_thread::sleep_for(dura);        //this_thread::sleep_for(dura);
    cout << "FuncA After sleep" << endl;
}

int main(int argc, char* argv[])
{
    cout << "Main before lock" << endl;
    unique_lock<mutex> mLock(m);
    auto a = std::thread(funcA);
    std::chrono::milliseconds dura(1000);//make sure thread is running
    std::this_thread::sleep_for(dura);        //this_thread::sleep_for(dura);
    mLock.unlock();//Unlocks thread 2's lock?
    cout << "Main After unlock" << endl;
    a.join();
    cout << "Main after a.join" << endl;
    return 0;
}

不确定为什么需要使用new来创建锁定&#39;。当然unique_lock<mutex> mlock(m);应该做的伎俩(当然mLock->mLock.的相应更改)。

答案 2 :(得分:3)

锁只是一个自动防护,以安全和理智的方式操作互斥锁。

你真正想要的是这段代码:

std::mutex m;

void f()
{
    std::lock_guard<std::mutex> lock(m);
    // ...
}

这有效地“同步”了对f的调用,因为进入它的每个线程都会阻塞,直到它设法获得互斥锁。

unique_lock只是lock_guard的增强版本:它可以构建为解锁,移动(感谢@MikeVine),它本身就是一个“可锁定的对象”,就像互斥体本身,因此它可以在变量std::lock(...)中用于以无死锁的方式同时锁定多个事物,并且可以由std::condition_variable管理(谢谢,@ syam)

但除非您有充分理由使用unique_lock,否则请使用lock_guard。一旦您需要升级到unique_lock,您就会知道原因。

答案 3 :(得分:0)

作为附注,上面的答案跳过了互斥锁的立即锁定和延迟锁定之间的区别:

#include<mutex>
::std::mutex(mu);
auto MyFunction()->void
{
   std::unique_lock<mutex> lock(mu); //Created instance and immediately locked the mutex
   //Do stuff....
}

auto MyOtherFunction()->void
{
   std::unique_lock<mutex> lock(mu,std::defer_lock); //Create but not locked the mutex
   lock.lock(); //Lock mutex
   //Do stuff....
   lock.unlock(); //Unlock mutex
}

MyFunction()显示广泛使用的立即锁定,而MyOtherFunction()显示延迟锁定。