Opened 6 years ago

Closed 6 years ago

#12386 closed Bugs (duplicate)

lock_error exception when using try_lock_for() on Windows

Reported by: Franz Beaune <franz@…> Owned by: viboes
Milestone: To Be Determined Component: thread
Version: Boost 1.61.0 Severity: Showstopper
Keywords: lock_error Cc:

Description

The following program immediately crashes with a lock_error exception on Windows:

#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>

using namespace boost;

shared_mutex mtx;

void f()
{
    while (true)
    {
        unique_lock<shared_mutex> lock(mtx, defer_lock);
        while (!lock.try_lock_for(chrono::milliseconds(1))) {}
    }
}

void g()
{
    while (true)
    {
        shared_lock<shared_mutex> lock(mtx, defer_lock);
        while (!lock.try_lock_for(chrono::milliseconds(1))) {}
    }
}

int main()
{
    const int N = 12;

    thread* threads[N];

    for (int i = 0; i < N; ++i)
        threads[i] = new thread(i % 2 ? f : g);

    for (int i = 0; i < N; ++i)
        threads[i]->join();

    return 0;
}

Callstack when the lock_error exception is thrown:

test.exe!boost::throw_exception<boost::lock_error>(const boost::lock_error & e)
test.exe!boost::shared_mutex::try_lock_until(const boost::chrono::time_point<boost::chrono::system_clock,boost::chrono::duration<__int64,boost::ratio<1,10000000> > > & tp)
test.exe!boost::shared_mutex::try_lock_until<boost::chrono::steady_clock,boost::chrono::duration<__int64,boost::ratio<1,1000000000> > >(const boost::chrono::time_point<boost::chrono::steady_clock,boost::chrono::duration<__int64,boost::ratio<1,1000000000> > > & t)
test.exe!boost::shared_mutex::try_lock_for<__int64,boost::ratio<1,1000> >(const boost::chrono::duration<__int64,boost::ratio<1,1000> > & rel_time)
test.exe!boost::unique_lock<boost::shared_mutex>::try_lock_for<__int64,boost::ratio<1,1000> >(const boost::chrono::duration<__int64,boost::ratio<1,1000> > & rel_time)

Boost.Thread code that throws the exception, in boost\thread\win32\shared_mutex.hpp:

bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
{
  for(;;)
  {
    state_data old_state=state;

    for(;;)
    {
      state_data new_state=old_state;
      if(new_state.shared_count || new_state.exclusive)
      {
        ++new_state.exclusive_waiting;
        if(!new_state.exclusive_waiting)
        {
            boost::throw_exception(boost::lock_error());     // <-- HERE
        }

        new_state.exclusive_waiting_blocked=true;
      }
      else
      {
        new_state.exclusive=true;
      }
      ...

Tested with Boost 1.55 and Boost 1.61, both compiled with Visual Studio 2013 in x64 mode, on Windows 10 64-bit.

Change History (4)

comment:1 by viboes, 6 years ago

Owner: changed from Anthony Williams to viboes
Status: newassigned

Hi,

I'm really sorry. I have never understood the original implementation.

Any help would be much appreciated.

comment:2 by viboes, 6 years ago

Can you try to comment

            boost::throw_exception(boost::lock_error());     // <-- HERE

and let me know what is the behavior?

comment:3 by viboes, 6 years ago

You can define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN to get the generic implementation. It is slower but IMHO it has less bugs.

comment:4 by viboes, 6 years ago

Resolution: duplicate
Status: assignedclosed

It seems that this is a duplicate of #11499.

Note: See TracTickets for help on using tickets.