Skip to content

Instantly share code, notes, and snippets.

@ot
Created April 21, 2024 13:12
Show Gist options
  • Save ot/64712433d33dab75559731f84dba5304 to your computer and use it in GitHub Desktop.
Save ot/64712433d33dab75559731f84dba5304 to your computer and use it in GitHub Desktop.
stdexec::static_thread_pool repro
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(deadlock_repro)
include(CPM.cmake)
CPMAddPackage(
NAME stdexec
GITHUB_REPOSITORY NVIDIA/stdexec
GIT_TAG main
)
CPMAddPackage(
NAME libunifex
GITHUB_REPOSITORY facebookexperimental/libunifex
GIT_TAG main
)
add_executable(deadlock deadlock.cpp)
target_link_libraries(deadlock STDEXEC::stdexec)
add_executable(deadlock_unifex deadlock.cpp)
target_compile_definitions(deadlock_unifex PRIVATE UNIFEX)
target_link_libraries(deadlock_unifex unifex)
add_executable(no_parallelism no_parallelism.cpp)
target_link_libraries(no_parallelism STDEXEC::stdexec)
add_executable(no_parallelism_unifex no_parallelism.cpp)
target_compile_definitions(no_parallelism_unifex PRIVATE UNIFEX)
target_link_libraries(no_parallelism_unifex unifex)
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
set(CPM_DOWNLOAD_VERSION 0.39.0)
set(CPM_HASH_SUM "66639bcac9dd2907b2918de466783554c1334446b9874e90d38e3778d404c2ef")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})
#ifdef UNIFEX
#include <unifex/just.hpp>
#include <unifex/on.hpp>
#include <unifex/static_thread_pool.hpp>
#include <unifex/sync_wait.hpp>
#include <unifex/then.hpp>
using namespace unifex;
#else
#include <exec/static_thread_pool.hpp>
#include <stdexec/execution.hpp>
using namespace stdexec;
using namespace exec;
#endif
int main() {
// XXX: 2 should be sufficient, but libunifex sometimes deadlocks. 3
// always works. Should be investigated separately.
static_thread_pool pool(3);
auto sched = pool.get_scheduler();
auto parent = [&] {
// parent is occupying one thread, but the pool should have more
// available for this to complete.
sync_wait(on(sched, just()));
};
sync_wait(on(sched, just() | then(parent)));
std::printf("Done\n");
}
#include <thread>
#include <vector>
#ifdef UNIFEX
#include <unifex/any_sender_of.hpp>
#include <unifex/async_scope.hpp>
#include <unifex/just.hpp>
#include <unifex/on.hpp>
#include <unifex/static_thread_pool.hpp>
#include <unifex/sync_wait.hpp>
#include <unifex/then.hpp>
using namespace unifex;
#define ON_EMPTY complete
#define SPAWN detached_spawn
#else
#include <exec/any_sender_of.hpp>
#include <exec/async_scope.hpp>
#include <exec/static_thread_pool.hpp>
#include <stdexec/execution.hpp>
using namespace stdexec;
using namespace exec;
#define ON_EMPTY on_empty
#define SPAWN spawn
#endif
int main() {
const size_t num_threads = 8;
static_thread_pool pool(num_threads);
auto sched = pool.get_scheduler();
async_scope scope;
auto parent = [&] {
std::printf("Parent\n");
auto child = [] {
std::printf("Child\n");
// Simulate a long-running (possibly CPU-intensive) task with a
// sleep.
std::this_thread::sleep_for(std::chrono::seconds(1));
};
for (size_t i = 0; i < num_threads; ++i) {
scope.SPAWN(on(sched, just() | then(child)));
}
};
sync_wait(on(sched, just() | then(parent)));
sync_wait(scope.ON_EMPTY());
std::printf("Done\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment