Skip to content

tf::Semaphore with exception may cause deadlocks in some situations #732

@olologin

Description

@olologin

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);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomershelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions