5

我在概念化unique_lock应该如何跨线程操作时遇到了一些麻烦。我试图做一个简单的例子来重新创建我通常会使用condition_variablefor 的东西。

#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

4 回答 4

11

unique_lock不应同时从多个线程访问。它不是以这种方式设计为线程安全的。相反,多个unique_locks (局部变量)引用相同的 global mutex。只有它mutex本身被设计为可以同时被多个线程访问。即便如此,我的声明也不包括~mutex().

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

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

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

于 2013-09-21T21:27:39.463 回答
5

这看起来不太对劲。首先,release是“在不解锁互斥锁的情况下解除关联”,这不太可能是您想要在那个地方做的事情。mutex这基本上意味着你不再有一个unique_lock<mutex>- 这将使它变得非常无用 - 这可能是你得到“访问冲突”的原因。

编辑:在对您的代码进行一些“按摩”并说服 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来创建锁tho'。当然unique_lock<mutex> mlock(m);应该做到这一点(当然还有相应的变化mLock->mLock.

于 2013-09-21T21:11:39.877 回答
3

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

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

std::mutex m;

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

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

Aunique_lock只是 的增强版本lock_guard:它可以被构造为解锁,移动(感谢@MikeVine),它本身就是一个“可锁定对象”,就像互斥锁本身一样,因此它可以用于例如可变参数std::lock(...)以无死锁的方式一次锁定多个事物,并且可以由std::condition_variable(感谢@syam)管理。

但除非你有充分的理由使用 a unique_lock,否则宁愿使用 a lock_guard。一旦你需要升级到 a unique_lock,你就会知道为什么。

于 2013-09-21T21:31:47.343 回答
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() 显示了延迟锁。

于 2016-09-15T07:27:04.713 回答