Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

try_lock_for not working as intended

I was fiddling around with some code in c++ that for some reason didn't want to work and i narrowed it down to this case:

#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
#include <iostream>

using namespace std;

void test()
{
  timed_mutex m;
  m.lock();
  std::cout << "Can i have the lock? " << m.try_lock() << std::endl;
  std::cout << "in test(), should block for 10 seconds" << std::endl;
  bool got_lock = m.try_lock_for(std::chrono::seconds(10));
  std::cout << "Now i've blocked, got the lock: " << got_lock << std::endl;
  m.unlock();
}

int main()
{
  thread t = thread(&test);
  t.join();

  return EXIT_SUCCESS;
}

The problem is that test() doesn't block at all, even though the try_lock returns false. Is there something i have overlooked or is this a bug in gcc or where should i go next to find out what's wrong? Thankful for any advice and help!

I compiled this little program like so: g++ -pthread -std=c++11 threads.cpp -o threads and if it's any help this is the version of gcc and my os:

g++ --version
g++ (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

uname -a
Linux *computername* 3.6.11-1-ARCH #1 SMP PREEMPT Tue Dec 18 08:57:15 CET 2012 x86_64 GNU/Linux
like image 343
lfxgroove Avatar asked Jan 19 '13 10:01

lfxgroove


1 Answers

Your code's behavior is undefined. std::timed_mutex has non-recursive ownership semantics. It's forbidden to acquire the lock (include try_lock family) second time on the same thread.

C++11 Standard 30.4.1.3.1 [thread.timedmutex.class]/p3/b2: (thanks to Howard Hinnant)

3 The behavior of a program is undefined if:

  • a thread that owns a timed_mutex object calls lock(), try_lock(), try_lock_for(), or try_lock_until() on that object, or

C++11 Standard 30.4.1.2 [thread.mutex.requirements.mutex]/p6-7:


EDITED:

how i am going to "work around this" or get it to behave the way i want? Should i use a recursive mutex instead?

Generally speaking, it's discouraged to acquire/release lock of mutex object in light of exception safty. If you use unique_lock object instead, owns_lock() member function may help you. Meanwhile recursive-mutex is useless for your purpose, because "recursive" means only "I(a thread) can acquire lock twice or more when I already own lock."

void test()
{
  std::timed_mutex m;
  std::unique_lock<decltype(m)> lk(m, std::defer_lock);

  // acquire lock
  lk.lock();
  // You can query locked status via unique_lock object
  std::cout << "Do I have own lock? " << lk.owns_lock() << std::endl;
  // release lock
  lk.unlock();
}
like image 151
yohjp Avatar answered Oct 11 '22 14:10

yohjp