0

When I am learning shared_mutex in C++17, I find a weired problem. If I call shared_lock twice in one thread, and call unique_lock in another thread, then my program will freeze. Like this:

std::mutex mutex;
std::shared_mutex s_mutex;

int i = 0;

void func() {
    auto lock = std::shared_lock(s_mutex);
    auto lock1 = std::shared_lock(s_mutex);
    ++i;
}

void func2() {
    auto lock = std::unique_lock(s_mutex);
    ++i;
}

int main() {
    auto t1 = std::thread([](){
        auto i = 10000;
        while(i--) {
            func();
        }
    });
    auto t2 = std::thread([](){
        auto i = 10000;
        while(i--) {
            func2();
        }
    });
    t2.join();
    t1.join();
    std::cout << i << std::endl;
    return 0;
}

This problem seems only appear on windows, I tried it on Arch linux, it works well.

I'm using g++.exe (Rev2, Built by MSYS2 project) 12.1.0.

I tried add cout after every lock like:

void func() {
    auto lock = std::shared_lock(s_mutex);
    std::cout << "t1 lock1\n";
    auto lock1 = std::shared_lock(s_mutex);
    std::cout << "t1 lock2\n";
    ++i;
}

Then I find it always freezes after t1 lock1\n, so I tried to step into lock1's constructor, and I find it freeze after this function:

static inline int
__gthread_active_p (void)
{
  return 1;
}

But I don't know why. Thanks in advance.

1 Answers1

5

Trying to lock the mutex again in a thread that already holds a lock on the mutex has undefined behavior.

This applies to all mutex types except the recursive* ones.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Specifically "If lock_shared is called by a thread that already owns the mutex in any mode (exclusive or shared), the behavior is undefined." from https://en.cppreference.com/w/cpp/thread/shared_mutex/lock_shared – François Andrieux Sep 24 '22 at 15:29
  • Typically, to prevent livelocks, as soon as thread tries to aquire exclusive lock, all new shared locks attempt are placed behind it in queue. If an attempt to aquire exclusive lock happens between two shared lock attempts in another thread, everything deadlocks: second thread waits for first thread to release first shared lock, while it stuck on attempt to aquire second shared lock, which will aquired only after second thread releases exclusive ownership. – Revolver_Ocelot Sep 24 '22 at 16:19