https://github.com/zelang-dev/c-threads
Emulated C11 threads & atomics, and features for cross-platform development
https://github.com/zelang-dev/c-threads
Last synced: 18 days ago
JSON representation
Emulated C11 threads & atomics, and features for cross-platform development
- Host: GitHub
- URL: https://github.com/zelang-dev/c-threads
- Owner: zelang-dev
- License: mit
- Created: 2025-10-19T20:10:54.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-10-19T22:58:54.000Z (9 months ago)
- Last Synced: 2025-10-20T02:59:12.743Z (9 months ago)
- Language: C
- Size: 766 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# C Threads
A `C` *library combining multiple packages for cross-platform development:*
- custom malloc with [rpmalloc](https://github.com/zelang-dev/rpmalloc).
- emulated C11 [thread](https://en.cppreference.com/w/c/thread) using [Pthreads](https://en.wikipedia.org/wiki/Pthreads), or [Pthreads4w](http://sourceforge.net/projects/pthreads4w/).
- emulated C11 [Atomic](https://en.cppreference.com/w/c/atomic) with [c-atomic](https://github.com/zelang-dev/c-atomic).
- general `Linux` compatibility *headers* for **Windows**, including a [mmap](https://man7.org/linux/man-pages/man2/mmap.2.html) compilation.
The **deps** folder has *Windows* **build/fork** of [pthread-win32](https://github.com/GerHobbelt/pthread-win32).
This library is a minimal, portable implementation of basic *threading* and *atomics* for `C`. They closely mimic the functionality and naming of the standard **C11 Thread**, and **C11 Atomic**, should be easily replaceable with the corresponding standard variants.
Custom **malloc** is a fork [rpmalloc](https://github.com/zelang-dev/rpmalloc) has no dependency on `thread_local` and can be compiled using [Tiny C compiler](https://github.com/zelang-dev/tinycc). All `malloc` operations are [lockless](https://preshing.com/20120612/an-introduction-to-lock-free-programming/), and implements a emulated **Thread-local storage** via macro `tls_storage(type, variable)` as:
_example.h_
```h
#include
#include
#include
#include
tls_storage_extern(int, gLocalVar);
```
_example.c_
```c
#include "example.h"
#define THREAD_COUNT 5
tls_storage(int, gLocalVar)
static int thread_local_storage(void *aArg) {
int thread = *(int *)aArg;
free(aArg);
int data = thread + rand();
*gLocalVar() = data;
usleep(10);
printf("thread #%d, gLocalVar is: %d\n", thread, *gLocalVar());
assert(*gLocalVar() == data);
return 0;
}
void emulated_tls(void) {
thrd_t t[THREAD_COUNT];
*gLocalVar() = 1;
for (int i = 0; i < THREAD_COUNT; i++) {
int *n = malloc(sizeof * n);
*n = i;
thrd_create(t + i, thread_local_storage, n);
}
for (int i = 0; i < THREAD_COUNT; i++) {
thrd_join(t[i], NULL);
}
assert(*gLocalVar() == 1);
}
int main(void) {
emulated_tls();
return 0;
}
```
> **cthreads.h** implements `thrd_local(type, variable)` macro, same behavior as above, but
> *will not emulate* if feature is *available* in your compiler, should be used for cross compatibility calling.
## Emulate/create/control `Thread Local Storage` via macros
The design of these *macros* follow normal behaviors when using `thread local storage`.
### In `rpmalloc.h`
The macro `tls_storage_extern(type, variable)` make function *proto*, and macro `tls_storage(type, variable)` will create functions as:
```h
C_API int rpmalloc_variable_tls;
C_API tls_storage_t rpmalloc_variable_tss;
C_API type* variable(void);
C_API void variable_delete(void);
```
The macro `tls_storage(type, variable)` will create the functions using:
```h
C_API int rpmalloc_tls_create(tls_storage_t *key, tls_dtor_t dtor);
C_API void rpmalloc_tls_delete(tls_storage_t key);
C_API void *rpmalloc_tls_get(tls_storage_t key);
C_API int rpmalloc_tls_set(tls_storage_t key, void *val);
```
### In `cthreads.h`
The macro `thrd_local_extern(type, variable)` make functions *proto*, and `thrd_local(type, variable)` create functions as:
**If compiler support *native* `thread_local`.**
```h
C_API thread_local type* thrd_variable_tls;
C_API void variable_del(void);
C_API void variable_update(type* value);
C_API bool is_variable_empty(void);
C_API type* variable(void);
```
Macro `thrd_local(type, variable)` also add.
```c
static thread_local type thrd_variable_buffer;
```
**If emulating `thread_local` is *detected/required*, will use platform `thread library` routines.**
```h
C_API int thrd_variable_tls;
C_API tss_t thrd_variable_tss;
C_API void variable_del(void);
C_API void variable_update(type* value);
C_API bool is_variable_empty(void);
C_API type* variable(void);
```
Macro `thrd_local(type, variable)` also add when *emulating*.
```c
static type thrd_variable_buffer;
```
- The macro `thrd_local_external(type, variable)` makes **non-pointer** *version* of above.
- The macro `thrd_static(type, variable)` makes local **non-extern** static function *version* of above.
## Installation
Any **commit** with an **tag** is considered *stable* for **release** at that *version* point.
If there are no *binary* available for your platform under **Releases** then build using **cmake**,
which produces **static** libraries by default.
You will need the *binary* stored under `built`, and `*.h` headers, or complete `include` *folder* if **Windows**.
### Linux
```shell
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug/Release -D BUILD_TESTS=OFF -D BUILD_EXAMPLES=OFF # use to not build tests and examples
cmake --build .
```
### Windows
```shell
mkdir build
cd build
cmake .. -D BUILD_TESTS=OFF -D BUILD_EXAMPLES=OFF # use to not build tests and examples
cmake --build . --config Debug/Release
```
### As cmake project dependency
> For **CMake** versions earlier than `3.14`, see
Add to **CMakeLists.txt**
```c
find_package(cthreads QUIET)
FetchContent_Declare(cthreads
URL https://github.com/zelang-dev/c-threads/archive/refs/tags/1.0.0.zip
URL_MD5 0f1c66f911f0912aa2a955a486952a8d
)
FetchContent_MakeAvailable(cthreads)
target_include_directories(${PROJECT_NAME}
AFTER PUBLIC $
$)
target_link_libraries(${PROJECT_NAME} PUBLIC cthreads)
```