jeudi 8 janvier 2015

packaged_task hanging on operator()

Compiling with gcc 4.7.2 on Ubuntu, compiled with -std=c++11 -O3 -pthread, I somehow created a deadlock in code that doesn't seem like it should ever run into that problem. I have a thread which just acquires a lock and then runs through a vector<function<void()>>, calling everything. Meanwhile, the main thread pushes std::packaged_task<int()>s onto it one-by-one and blocks on when that task's future returns. The tasks themselves are trivial (print and return).


Here is the full code. Running the app sometimes succeeds, but within a few tries will hang:



#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <functional>

std::unique_lock<std::mutex> lock() {
static std::mutex mtx;
return std::unique_lock<std::mutex>{mtx};
}

int main(int argc, char** argv)
{
std::vector<std::function<void()>> messages;
std::atomic<bool> running{true};

std::thread thread = std::thread([&]{
while (running) {
auto lk = lock();
std::cout << "[T] locked with " << messages.size() << " messages." << std::endl;
for (auto& fn: messages) {
fn();
}
messages.clear();
}
});

for (int i = 0; i < 1000000; ++i) {
std::packaged_task<int()> task([=]{
std::cout << "[T] returning " << i << std::endl;
return i;
});

{
auto lk = lock();
messages.emplace_back(std::ref(task));
}

task.get_future().get();
}

running = false;
thread.join();
}


Sample output:



[T] returning 127189
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
[T] returning 127190
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
[T] returning 127191
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 0 messages.
[T] locked with 1 messages.
... hangs forever ...


What's going on? Why does the call into packaged_task::operator() hang? Where is the deadlock? Is this a gcc bug?


Aucun commentaire:

Enregistrer un commentaire