Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VC++ implementation of std::promise

I have a strange issue with the VC++ implementation (both Visual Studio 2015 and 2017) of std::promise. set_value_at_thread_exit() does not seem to work as advertised - or maybe I misunderstand what the standard allows and what it does not. The following code will compile and run fine in clang but will crash when compiled with VS2015 (in the second block) or VS2017 (in the third block):

#include <future>
#include <thread>
#include <iostream>

int main()
{
    {
        std::cout << "Safe version... ";
        std::promise<int> promise;
        auto f = promise.get_future();

        std::thread
        (
            [](std::promise<int> p) 
            { 
                p.set_value(99); 
            }, 
            std::move(promise)
        )
        .detach();

        std::cout << f.get() << std::endl;
    }

    {
        std::cout << "Will crash VS2015... ";
        std::promise<int> promise;
        auto f = promise.get_future();

        std::thread(
            [p{ std::move(promise) }]() mutable 
            { 
                p.set_value_at_thread_exit(99); 
            }
        )
        .detach();

        std::cout << f.get() << std::endl;
    }

    {
        std::cout << "Will crash VS2017... ";
        std::promise<int> promise;
        auto f = promise.get_future();

        std::thread(
            [](std::promise<int> p) 
            { 
                p.set_value_at_thread_exit(99); 
            }, 
            std::move(promise)
        )
        .detach();

        std::cout << f.get() << std::endl;
    }
}

I have tried to make the differences visible by generously using newlines.

The problem seems to be that in the MS implementation, the destructor of the promise object inside the lambda function tries to update the shared state with a 'broken promise' exception even if set_value_at_thead_exit() was called. However, this fails and throws a system error in turn. It happens while trying to lock the associated mutex. If set_value_at_thread_exit() is not called, f.get() throws a future_error as expected.

Looking inside the MS implementation (VS2017) I found code that pretends to check whether the shared state is ready at thread exit but does nothing. So I am wondering whether this is a bug or whether I misunderstood the API and am supposed to ensure that the lifetime of the promise extends beyond the thread exit.

The latter seems to be what is happening in VS2017 in the second code block but not in VS2015 - probably due to implementation differences of std::thread?!

As mentioned above, the code runs fine in

clang: http://rextester.com/FEZDS24592
gcc: http://rextester.com/WFKE61563

but crashes in

the second block in VS2015: http://rextester.com/NODVFO14840
and the third block in VS2017. This can be tested here: http://webcompiler.cloudapp.net/

So basically I wonder whether I should file an issue or whether I will just be making a fool of myself because I am using the language all wrong?

Thanks

like image 321
A. Schoenle Avatar asked Oct 29 '22 23:10

A. Schoenle


1 Answers

Turns out that the xxx_at_thread_exit() has issues in most current implementations. See this visual studio community issue for details.

like image 154
A. Schoenle Avatar answered Nov 15 '22 07:11

A. Schoenle