Skip to content

Commit 226cdff

Browse files
committed
Enhance ReaderWriterLock with detailed documentation and add support for non-blocking write lock acquisition
1 parent 10dc1a2 commit 226cdff

4 files changed

Lines changed: 120 additions & 5 deletions

File tree

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ target_include_directories(${PROJECT_NAME}
2222
PUBLIC
2323
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
2424
$<INSTALL_INTERFACE:include>
25-
PRIVATE
26-
${OPENSSL_INCLUDE_DIR}
2725
)
2826

27+
if (BUILD_SHARED_LIBS)
28+
target_compile_definitions(${PROJECT_NAME} PUBLIC HEXA_UTILS_BUILD_SHARED=1)
29+
endif()
30+
2931
install(TARGETS ${PROJECT_NAME}
3032
EXPORT ${PROJECT_NAME}Config
3133
ARCHIVE DESTINATION lib

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Hexa.NET.Utilities.Native
2+
3+
The native C/C++ side of [Hexa.NET.Utilities](https://github.com/HexaEngine/Hexa.NET.Utilities), providing low-level synchronization primitives with a C-compatible API for P/Invoke interop from .NET.
4+
5+
## Features
6+
7+
- **ReaderWriterLock** — A high-performance, lock-free reader-writer lock built on C++20 atomics with:
8+
- Multiple concurrent readers
9+
- Exclusive writer access
10+
- Writer fairness (writers are not starved by incoming readers)
11+
- Try-lock variants for non-blocking acquisition
12+
- C-compatible ABI for use from C or via P/Invoke
13+
14+
## Requirements
15+
16+
- CMake 3.20 or later
17+
- A C++20-capable compiler (GCC, Clang, or MSVC)
18+
- C99 compiler support
19+
20+
## Building
21+
22+
```bash
23+
cmake -B build -DBUILD_SHARED_LIBS=ON
24+
cmake --build build
25+
```
26+
27+
To build as a static library:
28+
29+
```bash
30+
cmake -B build -DBUILD_SHARED_LIBS=OFF
31+
cmake --build build
32+
```
33+
34+
## Installation
35+
36+
```bash
37+
cmake --install build
38+
```
39+
40+
This installs the library to `lib/` and headers to `include/`.
41+
42+
## Project Structure
43+
44+
```
45+
include/
46+
common.h — Export macros and calling convention definitions
47+
ReaderWriterLock.h — ReaderWriterLock C API
48+
utils.h — Umbrella header (includes all public headers)
49+
src/
50+
ReaderWriterLock.cpp — C++20 atomic-based implementation
51+
CMakeLists.txt
52+
```
53+
54+
## License
55+
56+
MIT License — Copyright (c) 2024 Juna Meinhold. See [LICENSE.txt](LICENSE.txt) for details.

include/ReaderWriterLock.h

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,75 @@
55
#include <stdio.h>
66

77

8+
/**
9+
* @brief A lock-free reader-writer lock.
10+
*
11+
* Allows multiple concurrent readers or a single exclusive writer.
12+
* Writers are given fairness: once a writer is waiting, new readers
13+
* will block until the writer has acquired and released the lock.
14+
*
15+
* Must be initialized with ReaderWriterLock_Init() before use.
16+
*/
817
typedef struct ReaderWriterLock_t
918
{
1019
size_t storage;
1120
} ReaderWriterLock;
1221

1322

23+
/**
24+
* @brief Initializes a ReaderWriterLock.
25+
* @param cLock Pointer to the lock to initialize.
26+
*/
1427
HEXA_UTILS_API(void) ReaderWriterLock_Init(ReaderWriterLock* cLock);
28+
29+
/**
30+
* @brief Acquires a read lock, blocking until it is available.
31+
*
32+
* Blocks if a writer currently holds or is waiting for the lock.
33+
*
34+
* @param cLock Pointer to the lock.
35+
* @return 1 on success, -1 if the reader count would overflow.
36+
*/
1537
HEXA_UTILS_API(int) ReaderWriterLock_LockRead(ReaderWriterLock* cLock);
38+
39+
/**
40+
* @brief Attempts to acquire a read lock without blocking.
41+
*
42+
* @param cLock Pointer to the lock.
43+
* @return 1 if the read lock was acquired, 0 if a writer holds or is waiting
44+
* for the lock, -1 if the reader count would overflow.
45+
*/
1646
HEXA_UTILS_API(int) ReaderWriterLock_TryLockRead(ReaderWriterLock* cLock);
47+
48+
/**
49+
* @brief Releases a previously acquired read lock.
50+
* @param cLock Pointer to the lock.
51+
*/
1752
HEXA_UTILS_API(void) ReaderWriterLock_UnlockRead(ReaderWriterLock* cLock);
53+
54+
/**
55+
* @brief Acquires a write lock, blocking until all readers and other writers
56+
* have released the lock.
57+
* @param cLock Pointer to the lock.
58+
*/
1859
HEXA_UTILS_API(void) ReaderWriterLock_LockWrite(ReaderWriterLock* cLock);
19-
HEXA_UTILS_API(int) ReaderWriterLock_TryLockWrite(ReaderWriterLock* cLock);
60+
61+
/**
62+
* @brief Attempts to acquire a write lock without blocking.
63+
*
64+
* @param cLock Pointer to the lock.
65+
* @param preserveWriterFairness If true, the call blocks until all active
66+
* readers drain before returning success, preventing writer starvation.
67+
* If false, the call returns 0 immediately when readers are active.
68+
* @return 1 if the write lock was acquired, 0 if another writer already holds
69+
* the lock (or readers are active and @p preserveWriterFairness is false).
70+
*/
71+
HEXA_UTILS_API(int) ReaderWriterLock_TryLockWrite(ReaderWriterLock* cLock, bool preserveWriterFairness);
72+
73+
/**
74+
* @brief Releases a previously acquired write lock.
75+
* @param cLock Pointer to the lock.
76+
*/
2077
HEXA_UTILS_API(void) ReaderWriterLock_UnlockWrite(ReaderWriterLock* cLock);
2178

2279
#endif

src/ReaderWriterLock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,10 @@ HEXA_UTILS_API_INTERNAL(void) ReaderWriterLock_LockWrite(ReaderWriterLock* cLock
156156
lock->LockWrite();
157157
}
158158

159-
HEXA_UTILS_API_INTERNAL(int) ReaderWriterLock_TryLockWrite(ReaderWriterLock* cLock)
159+
HEXA_UTILS_API_INTERNAL(int) ReaderWriterLock_TryLockWrite(ReaderWriterLock* cLock, bool preserveWriterFairness)
160160
{
161161
ReaderWriterLockCpp* lock = reinterpret_cast<ReaderWriterLockCpp*>(cLock);
162-
return lock->TryLockWrite();
162+
return lock->TryLockWrite(preserveWriterFairness);
163163
}
164164

165165
HEXA_UTILS_API_INTERNAL(void) ReaderWriterLock_UnlockWrite(ReaderWriterLock* cLock)

0 commit comments

Comments
 (0)