mutex.try_lock()允许多个线程同时持有锁

时间:2015-09-24 20:00:03

标签: concurrency c++11

几个小时后,我的头发被撕掉了,看来我被c ++ 11的unique_lock的意外行为狠狠地殴打了。我一定有可怕的误会:

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>

#define N_THREADS 4
#define N_ITERATIONS 10000
#define N_LOOPS 1000000

class ThingMaJigger
{
public:
    void fight()    {
        if(m.try_lock()) {
            // more then one thread ends up here??!?!?
            printf("I'm the winner!\n" );
            m.unlock();
        } else {
            printf("Sleeping \n" );
        }
    }
private:
    std::mutex m;
};

void worker(ThingMaJigger* ar,int tIdx)
{
    ar->fight();
}

int main(int argc, char const *argv[])
{
    for (int _loop = 0; _loop < N_LOOPS; ++_loop) {
        std::vector<std::thread> ts;
        ThingMaJigger t;
        for (int i = 0; i < N_THREADS; ++i)
        {
            ts.emplace_back(worker,&t,i);
        }

        for (int i = 0; i < N_THREADS; ++i)
        {
            ts[i].join();
        }

        printf("\n");

    }
        return 0;
}

使用clang++ -std=c++11 -O2 -lpthread ./unique_lock.cpp

进行编译

clang 3.7.0,g ++ 5.1.1,两者的行为方式相同。

示例输出:

I'm the winner!
Sleeping 
Sleeping 
I'm the winner!

I'm the winner!
Sleeping 
I'm the winner!
Sleeping 

I'm the winner!
I'm the winner!
Sleeping 
Sleeping 

Kinda看起来像多个工人持有相同的锁 与此同时,不是吗?

http://en.cppreference.com/w/cpp/thread/mutex/try_lock说:

  

返回值

     

如果成功获取锁定,则为true,否则为false。

注意:即使没有其他人,也允许try_lock返回false 有锁。这不是什么意思。

2 个答案:

答案 0 :(得分:3)

这是按预期工作的。

印刷后“我是胜利者”,你正在解锁。这使得其他线程也有机会获得它。

如果你只想要一个线程“赢”,你还应该有一个变量来表明某人是否还赢了。在创建线程之前将其设置为false。任何获取锁的线程都会成功检查该变量,以查看是否有其他人获胜。

bool somebodyWon = false; // make sure this is set to false before
                          // threads get created

    if(m.try_lock()) {
        if (somebodyWon) {
            printf("Darn, someone beat me to it!\n");
        } else {
            printf("I'm the winner!\n");
            somebodyWon = true;
        }
        m.unlock();
    } else {
        printf("I didn't even get a chance! \n" );
    }
另一种方法,也是合法的,是从使用互斥锁转换为信号量,以便一个线程可以锁定对象,但让所有线程加入后父线程释放它。

答案 1 :(得分:0)

确信令人困惑。我们去购物吧!

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <unistd.h>

#define N_THREADS 4
#define N_ITERATIONS 10000
#define N_LOOPS 1000000

class ThingMaJigger
{
public:
    void fight()    {
        if(m.try_lock()) {
            // more then one thread ends up here??!?!?
            printf("I'm the winner!\n");
            usleep(1000000); // <<<< this. 
                             // or can unlock() before other's try_lock()
            m.unlock();
        } else {
            printf("Sleeping \n" );
        }
    }
private:
    std::mutex m;
};

void worker(ThingMaJigger* ar,int tIdx)
{
    ar->fight();
}

int main(int argc, char const *argv[])
{
    for (int _loop = 0; _loop < N_LOOPS; ++_loop) {
        std::vector<std::thread> ts;
        ThingMaJigger t;
        for (int i = 0; i < N_THREADS; ++i)
        {
            ts.emplace_back(worker,&t,i);
        }

        for (int i = 0; i < N_THREADS; ++i)
        {
            ts[i].join();
        }

        printf("\n");

    }
        return 0;
}