-
Notifications
You must be signed in to change notification settings - Fork 4
UserGuide
You need checkout source code from the trunk of the project repository, please find links at Source page or download archive from Releases page.
On Windows platform library usually can be simply included to the project. But on Posix platforms you have to add "pthread" library to your linker, for gcc it can be done by adding "-pthread" command line parameter.
Root directory of the project contain sub directory named "examples" where you can find Premake executable. You can make build scripts for system you like. For example if you need solution for VS2010 you need type in console "premake4 vs2010", after that you will get directory named "build_scripts" where VS projects and solution will be placed.
If you need only simple thread implementation, you could use cpptask::Thread
class, where you will need override Run method of the class. Or you can use cpptask::ThreadFunction
class, which take functor as constructor parameter.
#include <cpptask.h>
...
typedef void (*ThreadFunc)(void);
void ThreadFunc1()
{
//do work
}
...
spptask::ThreadFunction<ThreadFunc> mythread(&ThreadFunc1);
mythread.Start();
...
mythread.Wait();
...
Library provide only two types of atomics values:
-
cpptask::AtomicFlag
- class represents boolean values you can Set flag and Reset it.
#include <cpptask.h>
...
cpptask::AtomicFlag someFlag;
someFlag.Set();
if (someFlag.IsSet())
{
...
someFlag.Reset();
}
...
-
cpptask::AtomicNumber
- class represents c++ long value type you can atomicalyInc/Dec
andSetValue/GetValue
from it.
#include <cpptask.h>
...
cpptask::AtomicNumber counter;
counter.SetValue(10);
...
counter.Inc();
...
counter.Dec();
...
if (counter.GetValue() == 10)
{
...
}
...
Standard Mutex synchronization primitive:
#include <cpptask.h>
...
cpptask::Mutex guard;
...
{
cpptask::ScopedLock lock(&guard);
// synchronized work
...
}
...
long timeInMiliseconds = 10;
if (quard.WaitLock(timeInMiliseconds))
{
// wait for given time when mutex will be released and make a lock
...
quard.UnLock();
}
...
Windows API like Event synchronization primitive. One thread can wait for an event which can be signaled from many other threads.
#include <cpptask.h>
...
cpptask::Event event;
...
event.Signal();
...
event.Wait();
// do work work
event.Reset();
...
std::vector<MultWaitBase*> events;
int signaled = WaitForMultiple(events);
switch (signaled)
{
case -1:
// error
break;
case 0:
// first event is in signaled state
break;
case 1:
// second event is in signaled state
break;
}
Semaphore synchronization primitive. Multiple threads can signal and wait for semaphore. Each signal call will increase semaphore counter. Wait call will return if counter is non zero, and decrement it. If counter is zero Wait call will lock thread.
#include <cpptask.h>
...
cpptask::Semaphore sem;
...
sem.Signal();
...
event.Wait();
// do work work
...
std::vector<MultWaitBase*> events;
events.push_back(&sem);
int signaled = WaitForMultiple(sem);
switch (signaled)
{
case -1:
// error
break;
case 0:
// first event is in signaled state
break;
case 1:
// second event is in signaled state
break;
}
To schedule some job to the thread engine you can derive your class from the Task class and override Execute method. Then you have to create and initialize TaskManager
object. After that you have to add task to the manager and ask manager to start new jobs. Also Task class have method Wait which will lock you thread until task will be processed, and have method GetLastException
which you can call after wait to check if there were some exceptions.
#include "cpptask.h"
...
class MyTask : public Task
{
public:
virtual void Execute()
{
...
}
};
...
#include "cpptask.h"
...
cpptask::TaskThreadPool threadPool(THREADS_NUM);
...
cpptask::TaskManager* manager = cpptask::TaskManager::GetCurrent();
std::shared_ptr<MyTask> task(new MyTask);
manager.AddTask(task.get());
...
task->Wait(); //lock thread
...
manager.WaitTask(task.get()); //execute other tasks during waiting
Algorithm to execute in parallel some identical operations on container's elements.
#include <cpptask.h>
...
cpptask::TaskThreadPool threadPool(THREADS_NUM);
...
void func()(double& x)
{
//some operation
}
...
std::vector<double> array;
...
cpptask::ParallelFor(array.begin(), array.end(), func);
It is a some sort of parallel aggregation algorithm. The result of it will be the same as after std::accumulate. To use such algorithm you have to implement class with next three methods:
-
Copy constructor which will take as second parameter
cpptask::SplitMark
type - will be called to separate initial range to smaller ranges and divide them between threads. -
Function operator which will take Range object to perform some operations on this range
-
Join method which will be called to combine results from subranges processing.
#include <cpptask.h>
...
typedef std::vector<double> ArrayType;
class Accumulator
{
public:
Accumulator(double init) : res(init){}
Accumulator(const Accumulator& accumulator, cpptask::SplitMark)
: res(accumulator.res){}
void operator()(const cpptask::Range<ArrayType::iterator>& range)
{
ArrayType::iterator i = range.start;
ArrayType::iterator e = range.end;
for(; i != e; ++i)
{
res += i;
};
}
void Join(const Accumulator& accumulator)
{
res += accumulator.res;
}
double res;
};
...
Accumulator accumulator(0);
cpptask::ParallelReduce(array.begin(), array.end(), accumulator);
std::cout << accumulator.res;
...
Algorithm simply execute two functions in parallel.
#include <cpptask.h>
...
cpptask::ParallelInvoke(func1, func2);
If you want to get exceptions from threads or tasks you have to derive this exceptions from cpptask::Exception
class. After throwing such exception you will be able to get them from GetLastException
method of Thread and Task classes. If you will throw another exception they will be hidden, and there will be only one way to know Thread execution result call Thread::GetExitCode
method. Also all cpptask algorithms will automatically rethrow cpptask::Exception
after they finished.
New C++11 lambdas can be used in all algorithms of the library.
cpptask::ParallelInvoke([&](){//expensive work}, [&](){//expensive work});