The following code has a callback registered for some clean-up actions.
As soon as a stop is requested, the callback is invoked from main
and the thread exits.
The callback then waits a few ms and accesses the vector
on the thread stack which seems invalid since the thread no longer exists.
valgrind
and g -fsanitize=address
do not report any problem and the output of size()
is always as expected.
This makes me wonder if it is correct to access the vector on the thread stack as long as request_stop
in main
has not returned.
The output is:
thread finished 140037635319488
call back from: 140037639857984, size 1234
main finished 140037639857984
Note that the vector is accessed after the thread has finished its last line.
Question: is this code undefined behavior?
Some relevant quotes from the C standard might be helpful
#include <iostream>
#include <thread>
#include <vector>
#include <stop_token>
#include <chrono>
using namespace std::chrono_literals;
void thread_func(std::stop_token st)
{
std::vector<int> v;
std::stop_callback cb{st, [&v]
{
std::this_thread::sleep_for(1000ms);
for (int i=0; i<1234; i)
v.push_back(i);
std::cout << "call back from: " << std::this_thread::get_id()
<< ", size " << v.size() << '\n';
}};
while (!st.stop_requested())
{
// ...
}
std::cout << "thread finished " << std::this_thread::get_id() << '\n';
}
int main()
{
std::stop_source src;
auto t = src.get_token();
auto thr = std::jthread{thread_func, t};
std::this_thread::sleep_for(500ms);
bool b = src.request_stop();
std::cout << "main finished " << std::this_thread::get_id() << '\n';
}
CodePudding user response:
If the callback is being run from another thread (in your case the main thread in the request_stop()
call), then the destructor of std::stop_callback
blocks until that call is finished and destroys the stored callable only afterwards.
Because you declared v
before cb
, the vector will be destroyed only after the destructor of cb
returns during the stack unwinding when thread_func
returns after the stop request. The thread only exits after the stack unwinding.