You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tf::Semaphore with exception may cause deadlocks in some situations #732
Usage of tf::Semaphore with exception like below leads to a deadlock (where user always waits for task graph to finish), it happens because Semaphore keeps some of waiting tasks in its list, and the main task queue does not have those tasks.
void semaphore_complex1(int semaphore_size) {
tf::Executor executor(semaphore_size * 4);
tf::Taskflow taskflow;
tf::Semaphore semaphore(semaphore_size);
tf::Task init = taskflow.emplace([]() {});
for (size_t i = 0; i < semaphore_size * 4; ++i)
{
tf::Task A = taskflow.emplace([]() {});
tf::Task B = taskflow.emplace([]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
throw std::runtime_error("exception");
});
tf::Task C = taskflow.emplace([]() {});
tf::Task D = taskflow.emplace([]() {});
init.precede(A);
A.precede(B);
B.precede(C);
C.precede(D);
A.acquire(semaphore);
D.release(semaphore);
}
REQUIRE(semaphore.value() == semaphore_size);
auto future = executor.run(taskflow);
auto fn = [&]() {
auto res = future.wait_for(std::chrono::seconds(60));
if (res == std::future_status::timeout)
{
FAIL("Timeout");
}
FAIL("No exception?!");
};
// when B throws the exception, D will not run and thus semaphore is not released
REQUIRE_THROWS_WITH_AS(fn(), "exception", std::runtime_error);
REQUIRE(semaphore.value() == 0);
// reset the semaphore to a clean state before running the taskflow again
semaphore.reset();
REQUIRE(semaphore.value() == semaphore_size);
// run it again
REQUIRE_THROWS_WITH_AS(fn(), "exception", std::runtime_error);
}
TEST_CASE("Exception.Semaphore.Complex.4threads" * doctest::timeout(300)) {
semaphore_complex1(4);
}
I'm trying to think through solutions to this problem here. I would love someone who is more experienced to give their thoughts on the matter.
In the taskflow shown above, when the exception is thrown, should the taskflow
A. Cancel all of its work that it is trying to do
or
B. Find the cancelled nodes' semaphores that were to be released and do clean-up on them?
I think A makes more sense. Again, I'm not an expert, but B feels fishy to me.
If A is the way to go, how do you interrupt nodes that are waiting to acquire semaphores?
Activity
aman-coder03 commentedon Nov 28, 2025
Can I work on this issue?
CalebLarsen commentedon Dec 10, 2025
I'm trying to think through solutions to this problem here. I would love someone who is more experienced to give their thoughts on the matter.
In the taskflow shown above, when the exception is thrown, should the taskflow
A. Cancel all of its work that it is trying to do
or
B. Find the cancelled nodes' semaphores that were to be released and do clean-up on them?
I think A makes more sense. Again, I'm not an expert, but B feels fishy to me.
If A is the way to go, how do you interrupt nodes that are waiting to acquire semaphores?