Skip to content

Commit af9d06e

Browse files
committed
add critical sections example
1 parent 1fdcc4c commit af9d06e

4 files changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
project(chroma-examples LANGUAGES CXX)
3+
4+
set(CMAKE_CXX_STANDARD 26)
5+
set(CMAKE_CXX_STANDARD_REQUIRED True)
6+
7+
find_package(chroma REQUIRED)
8+
9+
add_executable(chroma-critical-section src/main.cpp)
10+
target_link_libraries(chroma-critical-section PRIVATE chroma::chroma)
11+
target_include_directories(chroma-critical-section PRIVATE include)
12+
13+
# WORKAROUND:
14+
# Conan needs the new CMakeConfigDeps generator to handle INTERFACE options etc properly
15+
target_compile_features(chroma-critical-section PRIVATE cxx_std_26)
16+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
17+
target_compile_options(chroma-critical-section PRIVATE "-stdlib=libc++" "-freflection-latest")
18+
target_link_options(chroma-critical-section PRIVATE "-stdlib=libc++")
19+
target_link_libraries(chroma-critical-section PRIVATE "c++abi")
20+
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
21+
target_compile_options(chroma-critical-section PRIVATE "-freflection")
22+
endif()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from conan import ConanFile
2+
from conan.tools.cmake import CMake, cmake_layout
3+
4+
class Consumer(ConanFile):
5+
name = "chroma-critical-section"
6+
version = "0.1"
7+
settings = "os", "compiler", "build_type", "arch"
8+
requires = "chroma/0.0.1"
9+
generators = "CMakeDeps", "CMakeToolchain"
10+
11+
def layout(self):
12+
cmake_layout(self)
13+
14+
def build(self):
15+
cmake = CMake(self)
16+
cmake.configure()
17+
cmake.build()
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
#pragma once
3+
#include <mutex>
4+
#include <utility>
5+
#include <chroma>
6+
7+
class locked_context {
8+
public:
9+
explicit locked_context(std::mutex& mtx) : m_mutex(&mtx) { m_mutex->lock(); }
10+
11+
~locked_context() {
12+
if (m_mutex != nullptr) {
13+
m_mutex->unlock();
14+
}
15+
}
16+
17+
locked_context(locked_context&& other) noexcept
18+
: m_mutex(std::exchange(other.m_mutex, nullptr)) {}
19+
20+
locked_context& operator=(locked_context&& other) noexcept {
21+
if (this != &other) {
22+
if (m_mutex != nullptr) {
23+
m_mutex->unlock();
24+
}
25+
m_mutex = std::exchange(other.m_mutex, nullptr);
26+
}
27+
return *this;
28+
}
29+
30+
locked_context(const locked_context&) = delete;
31+
locked_context& operator=(const locked_context&) = delete;
32+
33+
[[nodiscard]] chroma::color<locked_context> context() const {
34+
if (m_mutex == nullptr) {
35+
throw std::runtime_error("Invalid context");
36+
}
37+
return {};
38+
}
39+
40+
static constexpr auto error_message = "not in locked context";
41+
42+
private:
43+
std::mutex* m_mutex;
44+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <chroma>
2+
#include <lock.hpp>
3+
4+
void still_in_critical_section(callable_from<locked_context> = {}) {
5+
// ...
6+
}
7+
8+
void must_be_locked(callable_from<locked_context> = {}) {
9+
// call can be implicit, lock is still held
10+
still_in_critical_section();
11+
}
12+
13+
int main() {
14+
std::mutex mtx;
15+
{
16+
locked_context lock(mtx); // acquire lock
17+
18+
// get color for the acquired lock
19+
must_be_locked(lock.context());
20+
}
21+
}

0 commit comments

Comments
 (0)