jeudi 24 septembre 2015

mutex.try_lock() lets multiple threads hold the lock simultaneously

After hours tearing my hair out, it appears I've been savagely mauled by unexpected behaviour from c++11's unique_lock. I must have horribly misunderstood something :

#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;
}

Compile with clang++ -std=c++11 -O2 -lpthread ./unique_lock.cpp

clang 3.7.0, g++ 5.1.1, both behave in the same way.

Example output:

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 looks like multiple workers holding the same lock at the same time, don't it?

http://ift.tt/1FiWPvq says:

Return value

true if the lock was acquired successfully, otherwise false.

Note: try_lock is allowed to return false even if no one else has the lock. That's not what this is about.

Aucun commentaire:

Enregistrer un commentaire