简体   繁体   中英

Unexpected behavior using std::try_to_lock

I get surprising and conflicting behavior when I try to run the following code.

#include <iostream>
#include <mutex>

int main() {
    std::mutex mtx;
    std::unique_lock<std::mutex> lock1(mtx);
    std::unique_lock<std::mutex> lock2(mtx, std::try_to_lock);

    std::cout << "lock1 owns lock: " << lock1.owns_lock() << std::endl;
    std::cout << "lock2 owns lock: " << lock2.owns_lock() << std::endl;
}

When I run this on my computer (linux with either clang++ 4.0.1 or g++ 7.3.0) it prints out that both lock1 and lock2 own the lock (surprising). When I run this on cpp.sh it says that lock1 does own, but lock2 does not own the lock (what I expected).

All are using C++11 and -Wall without optimizations.

As stated in documentation for std::unique_lock constructor:

  1. Tries to lock the associated mutex without blocking by calling m.try_lock(). The behavior is undefined if the current thread already owns the mutex except when the mutex is recursive.

Emphasis is mine. Since std::mutex is not recursive you have undefined behaviour - std::mutex::try_lock()

If try_lock is called by a thread that already owns the mutex, the behavior is undefined.

As was answered here, locking mutex that is already owned by the current thread is an undefined behavior according to the C++ standard, but it seems that you know that your implementation is based on POSIX Threads, which has a different set of requirements:

The pthread_mutex_trylock() function shall be equivalent to pthread_mutex_lock() , except that if the mutex object referenced by mutex is currently locked ( by any thread, including the current thread ), the call shall return immediately.

What you are observing is most likely caused by you not building your code using -pthread flag. GNU C++ library detects if program is linked against libpthread.so and if it is not, then all calls to lock / unlock functions are turned into no-op.

You can find some information here :

__gthread_mutex_lock is a one-line function that forwards to pthread_mutex_lock . Using GNU libc if you don't link to libpthread.so then pthread_mutex_lock is a no-op function that does nothing . It is quicker to just call it than to spend time checking if threads are active.

Or you can check the source code for std::mutex::lock in your header files yourself. You will see something like this:

void
lock()
{
  int __e = __gthread_mutex_lock(&_M_mutex);

  // EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
  if (__e)
     __throw_system_error(__e);
}

static inline int
__gthread_mutex_lock (__gthread_mutex_t *__mutex)
{
  if (__gthread_active_p ())
    return __gthrw_(pthread_mutex_lock) (__mutex);
  else
    return 0;
}

Function __gthread_active_p will return 0 if libpthread.so is not present in the current process, making mutex locking a no-op.

Adding -pthread will fix your problem, but you shouldn't rely on this - as demonstrated by your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM