[Bug libstdc++/60966] std::call_once sometime hangs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966 Hideaki Kimura changed: What|Removed |Added CC||hideaki.kimura at gmail dot com --- Comment #11 from Hideaki Kimura --- Hi, I'm also (seemingly) hitting this issue. When I run my program with valgrind, I get what Thomas reported. ==22319== Invalid read of size 4 ==22319==at 0x370940D201: pthread_once (pthread_once.S:111) ==22319==by 0x4C80524: (gthr-default.h:699) ... ==22319== Address 0x52c52a4 is 132 bytes inside a block of size 136 free'd ==22319==at 0x4A07991: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==22319==by 0x4C82456: ... (shared_ptr_base.h:161) ==22319==by 0x370C4B52AF: execute_native_thread_routine (thread.cc:84) ==22319==by 0x3709407F32: start_thread (pthread_create.c:309) ==22319==by 0x37090F4DEC: clone (clone.S:111) ==22319== My environment is Fedora 20, x86_64, g++ (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7). Any workaround?
[Bug libstdc++/60966] std::call_once sometime hangs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966 --- Comment #14 from Hideaki Kimura --- (In reply to Jonathan Wakely from comment #13) > This means you are waiting on an object that has gone out of scope. WIthout > more information it's not possible to tell if this is a bug in your program > or the standard libary. > > I'll try to reproduce it with Thomas's code... Hey Jonathan, I'm not sure if this helps, but could you try the following code snippet? #include #include #include #include struct DummyTask { DummyTask(int id) : id_(id) {} int id_; std::promise pr; }; const int THREADS = 100; void run_task(DummyTask* task) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); task->pr.set_value(); } void wait_for_task(DummyTask* task) { task->pr.get_future().wait(); } int main() { std::vector tasks; std::vector threads; for (int i = 0; i < THREADS; ++i) { DummyTask* task = new DummyTask(i); tasks.push_back(task); threads.push_back(new std::thread(run_task, task)); } for (int i = 0; i < THREADS; ++i) { wait_for_task(tasks[i]); // Because we returned from wait_for_task for this task, run_task is surely done. // No one else is referring to the task. So, even before threads[i]->join(), // it should be safe to delete it now. delete tasks[i]; // but here you get an invalid read! } for (int i = 0; i < THREADS; ++i) { threads[i]->join(); delete threads[i]; } return 0; } Run it a few times on valgrind. You will see what I got. If you move threads[i]->join() to the line before delete tasks[i], you don't get the issue. [Assuming that I'm not terribly missing something..] My bet is that std::promise puts something on thread-local, which causes some issue when std::promise's destructor is called before the corresponding thread's join() is called.
[Bug libstdc++/60966] std::call_once sometime hangs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966 --- Comment #17 from Hideaki Kimura --- (In reply to Jonathan Wakely from comment #16) > promise::get_future() is a non-const function that modifies the promise > object, therefore it must not be called while any other object is accessing > the promise. Oh, is it the design of promise::get_future/set_value? I so far don't see any reference that clarifies either way (most document just mentions about difference between future/shared_future) Taking a glance at boost::promise code, I got an impression that their code is safe against concurrent get_future() and set_value() because get_future() either does atomic swap in lazy_init() or does nothing (allocated in constructor). I guess that's why Thomas observed that the issue doesn't happen in boost::promise. I'm not sure what the C++ standard says. I haven't seen a single human being who has read it through.
[Bug libstdc++/60966] std::call_once sometime hangs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60966 --- Comment #22 from Hideaki Kimura --- Ah, you are right, set_value() might have context switch after signaling before exitting. ... ah, and that's why what Thomas initially posted could also see a hang. { // copy-paste again to refresh memory, with some simplification std::promise promise; auto future = promise.get_future(); std::async or thread ( {promise.set_value();}); future.get(); } The user of std::promise must make sure the asynchronous thread has surely exitted at least from promise.set_value() before std::promise gets out of scope. promise/future is a handy way to synchronize between threads, but to use it one must protect it with thread synchronization..? That's quite tedious. I've just seen the patch as of writing this comment. I guess it solves the issue? (In reply to Jonathan Wakely from comment #19) > (In reply to Jonathan Wakely from comment #16) > > The easiest fix is to call get_future() before passing the task into a new > > thread, and store it in a std::vector> > > Actually this only hides the error (by ensuring the shared state is not > deleted > because there is a future object still referring to it) but the fundamental > problem with that code remains: > > You are calling the promise destructor before the call to set_value() > completes. > > You are assuming that as soon as the shared state becomes ready the promise > is no longer in use, but that's not true. After the shared state is made > ready the rest of the set_value() function runs, which accesses members of > the shared state. If you destroy the promise (and it has the only reference > to the shared state) then it will destroy its members while they are still > being used. > > This is a bug in your code, std::promise is like any other type: you must > not delete it while another thread is still using it.