An open API service indexing awesome lists of open source software.

https://github.com/nem0/lucy_job_system

Fiber-based job system with extremely simple API
https://github.com/nem0/lucy_job_system

fibers job multithreading

Last synced: about 2 months ago
JSON representation

Fiber-based job system with extremely simple API

Awesome Lists containing this project

README

        

# Lucy Job System

**This is outdated compared to [Lumix Engine](https://github.com/nem0/LumixEngine/blob/master/src/engine/job_system.h). Use that instead.**

Fiber-based job system with extremely simple API.

It's a standalone version of job system used in [Lumix Engine](https://github.com/nem0/lumixengine).
Only Windows is supported now, although the Lumix Engine version has Linux support, I have to copy it here yet.

## Demo
Create a solution with ```create_solution_vs2017.bat```. The solution is in ```build/tmp/```. Open the solution, compile and run.

```cpp
#include "lucy.h"
#include
#include
#include

std::mutex g_mutex;
std::condition_variable g_finished;
std::mutex g_finished_mutex;

void print(const char* msg)
{
std::lock_guard lock(g_mutex);
printf(msg);
printf("\n");
}

void jobB(void*)
{
print("B begin");
print("B end");
}

void jobA(void*)
{
print("A begin");
lucy::SignalHandle finished = lucy::INVALID_HANDLE;
for(int i = 0; i < 10; ++i) {
lucy::run(nullptr, jobB, &finished);
}
lucy::wait(finished);
print("A end");
g_finished.notify_all();
}

int main(int argc, char* argv[])
{
lucy::init();
lucy::run(nullptr, jobA, nullptr);
std::unique_lock lck(g_finished_mutex);
g_finished.wait(lck);
lucy::shutdown();
}
```

## Integration
Just put lucy.h and lucy.cpp in your project and you are good to go.

## Docs

See ```src/main.cpp``` for an example.

### Initialization / shutdown

```lucy::init()``` must be called before any other function from lucy namespace
```lucy::shutdown()``` call this when you don't want to run any more jobs. Make sure all jobs are finished before calling this, since it does not wait for jobs to finish.

### Jobs

Job is a function pointer with associated void data pointer. When job is executed, the function is called and the data pointer is passed as a parameter to this function.

```lucy::run``` push a job to global queue

```cpp
int value = 42;
lucy::run(&value, [](void* data){
printf("%d", *(int*)data);
}, nullptr);
```

This prints ```42```. Eventually, after the job is finished, a signal can be triggered, see signals for more information.

### Signals

```cpp
lucy::SignalHandle signal = lucy::INVALID_HANDLE;
lucy::wait(signal); // does not wait, since signal is invalid
lucy::incSignal(&signal);
lucy::wait(signal); // wait until someone calls lucy::decSignal, execute other jobs in the meantime
```

```cpp
lucy::SignalHandle signal = lucy::INVALID_HANDLE;
for (int i = 0; i < N; ++i) {
lucy::incSignal(&signal);
}
lucy::wait(signal); // wait until lucy::decSignal is called N-times
```

If a signal is passed to ```lucy::run``` (3rd parameter), then the signal is automatically incremented. It is decremented once all the job is finished.

```cpp
lucy::SignalHandle finished = lucy::INVALID_HANDLE;
for(int i = 0; i < 10; ++i) {
lucy::run(nullptr, job_fn, &finished);
}
lucy::wait(finished); // wait for all 10 jobs to finish
```

There's no need to destroy signals, it's "garbage collected".

Signals can be used as preconditions to run a job. It means a job starts only after the signal is signalled:

```cpp
lucy::SignalHandle precondition = getPrecondition();
lucy::runEx(nullptr, job_fn, nullptr, precondition, lucy::ANY_WORKER);
```

is functionally equivalent to:

```cpp
void job_fn(void*) {
lucy::wait(precondition);
dowork();
}
lucy::run(nullptr, job_fn, nullptr);
```

However, the ```lucy::runEx``` version has better performance.

Finally, a job can be pinned to specific worker thread. This is useful for calling APIs which must be called from the same thread, e.g. OpenGL functions or WinAPI UI functions.

```cpp
lucy::runEx(nullptr, job_fn, nullptr, lucy::INVALID_HANDLE, 3); // run on worker thread 3
```