Opened 8 years ago

Closed 5 years ago

#10964 closed Bugs (fixed)

future<future<T>>::unwrap().then() Deadlocks

Reported by: code@… Owned by: viboes
Milestone: To Be Determined Component: thread
Version: Boost 1.57.0 Severity: Problem
Keywords: Cc: contact@…

Description

The shared_state returned by unwrap() doesn't appear to propagate continuation information properly. The following code will deadlock, but the continuations should be immediately invoked.

struct TestCallback
{
    typedef boost::future<void> result_type;

    result_type operator()(boost::future<void> future) const
    {
        future.get();
        return boost::make_ready_future();
    }

    result_type operator()(boost::future<boost::future<void>> future) const
    {
       future.get();
       return boost::make_ready_future();
    }
};

int main()
{
    boost::make_ready_future().then(
        TestCallback()).unwrap().then(TestCallback()).get();
    return 0;
}

Change History (22)

comment:1 by viboes, 8 years ago

Owner: changed from Anthony Williams to viboes
Status: newassigned

comment:3 by viboes, 8 years ago

The following doesn't work after the patch

    boost::async(f).then(
        TestCallback()).unwrap().then(TestCallback()).get();

comment:5 by viboes, 8 years ago

Resolution: fixed
Status: assignedclosed

comment:6 by viboes, 7 years ago

Milestone: Boost 1.58.0To Be Determined
Resolution: fixed
Status: closedreopened

The problem is yet there

See http://www.boost.org/development/tests/develop/developer/output/Flast-FreeBSD10-gcc-6-0-0~gnu++11-boost-bin-v2-libs-thread-test-test_10964-test-gcc-6-0-0-debug-threading-multi.html

and

http://www.boost.org/development/tests/develop/developer/output/Flast-FreeBSD10-gcc-5-1-0~gnu++11-boost-bin-v2-libs-thread-test-ex_future_unwrap-test-gcc-5-1-0-debug-threading-multi.html

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
  what():  boost: mutex lock failed in pthread_mutex_lock: Resource deadlock avoided

comment:7 by viboes, 7 years ago

Status: reopenednew

comment:8 by viboes, 7 years ago

Status: newassigned

comment:9 by code@…, 7 years ago

I can look into this if you don't have the time.

comment:10 by viboes, 7 years ago

Yes, please. Any help will be welcome, an hint, a trace back, requesting for something you don't understand and find weird.

It would be great if you test with the branch https://github.com/boostorg/thread/tree/feature/make_executors_copyable, which make use of non-blocking futures also.

BTW, what is your name?

comment:11 by code@…, 7 years ago

Lee Clagett. I've discussed Futures with you on the mailing list before. Unfortunately my name is after the @ in my email, so it doesn't show here, didn't think about that.

comment:12 by viboes, 7 years ago

Glad to meet you Lee.

comment:13 by viboes, 7 years ago

Resolution: fixed
Status: assignedclosed

It seems that https://github.com/boostorg/thread/commit/60a8cb9b5c69423ee0bea403cacc971606575f01 fixes it.

I don't see anymore the errors.

comment:14 by code@…, 7 years ago

I noticed that too. Looks like this is going to be a fun one.

I tried to recreate this issue on OSX (closest to FreeBSD I had), but no luck. And Clang's tsan isn't supported on OSX, at least on my version. I now have a FreeBSD VM, but I just found out that tsan isn't supported on this platform either! I'll run the tests on this system anyway, before moving to one my Linux systems with tsan. After that its begging Flast to do some investigating for me with some code auditing on the side.

comment:15 by code@…, 7 years ago

Oh, and is it possible that he had a bad build? I feel like that may have happened on one of his systems, I'll try to ask him that ASAP.

comment:16 by Mattéo Delabre ✏ <contact@…>, 5 years ago

I’ve encountered a similar problem while using deferred continuations (see https://stackoverflow.com/questions/44748568/boostfuture-deferred-continuation-unwrapping-deadlocks).

#define BOOST_THREAD_VERSION 5

#include <iostream>
#include <boost/thread/future.hpp>

int main(int argc, char* argv[])
{
    boost::promise<int> promise;
    boost::future<int> future = promise.get_future();

    promise.set_value(42);

    int result = future.then(
        boost::launch::deferred,
        [](boost::future<int> result)
        {
            return boost::make_ready_future(result.get());
        }
    ).unwrap().get();

    std::cout << "Result is: " << result << std::endl;
    return 0;
}

This code causes a deadlock. If the launch policy is replaced by boost::launch::async, it works as intended.

comment:17 by Mattéo Delabre ✏ <contact@…>, 5 years ago

Resolution: fixed
Status: closedreopened

comment:18 by Mattéo Delabre ✏ <contact@…>, 5 years ago

Cc: contact@… added

comment:19 by viboes, 5 years ago

@Matteo Please, create a new issue, as the case you are describing is different than the original one.

comment:20 by viboes, 5 years ago

See "VS 2017.4 Preview deadlocks on Test 10964" https://github.com/boostorg/thread/issues/132

comment:21 by viboes, 5 years ago

Matteo, could you try with

#define BOOST_THREAD_VERSION 4

Version 5 has not been delivered officially.

The main difference of version 5 would be that BOOST_THREAD_ASYNC_FUTURE_WAITS is not defined (BOOST_THREAD_FUTURE_BLOCKING neither).

          ~future_async_shared_state_base()
          {
#ifdef BOOST_THREAD_FUTURE_BLOCKING
            join();
#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS
            unique_lock<boost::mutex> lk(this->mutex);
            while(!this->done)
            {
              this->waiters.wait(lk);
            }
#endif
          }

but I have no tested it too much. It seems that there are some big implications.

comment:22 by viboes, 5 years ago

Resolution: fixed
Status: reopenedclosed
Note: See TracTickets for help on using tickets.