Skip to content

Instantly share code, notes, and snippets.

@cleoold
Last active April 23, 2021 02:14
Show Gist options
  • Save cleoold/67f37dbd1d1b2421b4ae5067c39e9f6d to your computer and use it in GitHub Desktop.
Save cleoold/67f37dbd1d1b2421b4ae5067c39e9f6d to your computer and use it in GitHub Desktop.
raii safe c++ thread
#pragma once
// source: Scott Meyers - Effective Modern C++-O'Reilly item 37
// compile flag: -lpthread -Wall -std=c++20
#include <thread>
#include <type_traits>
// RAII managed thread class
class thread_raii {
public:
enum class dtor_action {
join, detach
};
explicit thread_raii(dtor_action action_, std::thread &&thread_) noexcept
: action{action_}, thread{std::move(thread_)}
{}
template<class Fn, class ...Args
#ifdef __cpp_concepts
> requires std::is_invocable_v<Fn, Args...>
#else
, std::enable_if_t<std::is_invocable_v<Fn, Args...>, int> = 0>
#endif
explicit thread_raii(dtor_action action_, Fn &&f, Args &&...args)
: thread_raii{action_, std::thread{std::forward<Fn>(f), std::forward<Args>(args)...}}
{}
thread_raii(thread_raii &&) noexcept = default;
thread_raii &operator=(thread_raii &&o) noexcept {
std::swap(action, o.action);
std::swap(thread, o.thread);
return *this;
};
// either join or detach when destructed to avoid program termination
~thread_raii() {
if (thread.joinable()) {
switch (action) {
case dtor_action::join:
thread.join(); // noexcept?
break;
case dtor_action::detach:
default:
thread.detach();
break;
}
}
}
auto &get() noexcept {
return thread;
}
private:
dtor_action action;
std::thread thread; // thread is constructed last to ensure it can use
// proper states
};
#include <iostream>
#include <vector>
#include "thread_raii.hpp"
int main() {
auto ths = std::vector<thread_raii>{};
for (auto i = 0; i < 5; ++i) {
ths.emplace_back(thread_raii::dtor_action::join, [](auto x) {
auto s = std::to_string(x) + '\n';
std::cout << s;
}, i);
}
auto thz = std::move(ths);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment