I am working on a Thread Pool and have been trying to work out the best way to handle thread safety. I would like to know if my mutex usage is "Correct" and if not how I should change it. I am using the c++11 std::thread and std::mutex.
this is the Worker Threads function. It Locks on the first line.
void Worker::work(void){
std::lock_guard<std::mutex> mutex(_lock);
while (_working) {
while (!_tasks.empty()) {
Job_t* job = _tasks.front();
if (!job->Complete()) {//the same job cannot be scheduled twice. It must be finnished before it is scheduled again.
(*job)();
}
_tasks.pop();
}
}
}
this is My Job classes function that does whatever "job" the job was created to do.
void operator()(void){
_returnValue = func(_args,sequence_generator::gen_seq<sizeof...(arguments)>{});
}
template <typename... Args, int... Is>
returnType func(std::tuple<Args...>& tup, sequence_generator::_index<Is...>)
{
std::lock_guard<std::mutex> mutex(_lock);
_complete=true;
return _function(std::get<Is>(tup)...);
}
There is a lot more to the design so i will post a link to my git repo for the project.
I would like to know if having the function work() lock and then having the func() lock as well is needed or even a good idea?
here is the repo
EDIT:
So the call order evaluates out to be...
Worker::work();
//which internally calls the
operator()();
//which internally calls the
func();
Related
I need to work with several objects, where each operation may take a lot of time.
The processing could not be placed in a GUI (main) thread, where I start it.
I need to make all the communications with some objects on asynchronous operations, something similar to std::async with std::future or QtConcurrent::run() in my main framework (Qt 5), with QFuture, etc., but it doesn't provide thread selection. I need to work with a selected object (objects == devices) in only one additional thread always,
because:
I need to make a universal solution and don't want to make each class thread-safe
For example, even if make a thread-safe container for QSerialPort, Serial port in Qt cannot be accessed in more than one thread:
Note: The serial port is always opened with exclusive access (that is, no other process or thread can access an already opened serial port).
Usually a communication with a device consists of transmit a command and receive an answer. I want to process each Answer exactly in the place where Request was sent and don't want to use event-driven-only logic.
So, my question.
How can the function be implemented?
MyFuture<T> fut = myAsyncStart(func, &specificLiveThread);
It is necessary that one live thread can be passed many times.
Let me answer without referencing to Qt library since I don't know its threading API.
In C++11 standard library there is no straightforward way to reuse created thread. Thread executes single function and can be only joined or detachted. However, you can implement it with producer-consumer pattern. The consumer thread needs to execute tasks (represented as std::function objects for instance) which are placed in queue by producer thread. So if I am correct you need a single threaded thread pool.
I can recommend my C++14 implementation of thread pools as tasks queues. It isn't commonly used (yet!) but it is covered with unit tests and checked with thread sanitizer multiple times. The documentation is sparse but feel free to ask anything in github issues!
Library repository: https://github.com/Ravirael/concurrentpp
And your use case:
#include <task_queues.hpp>
int main() {
// The single threaded task queue object - creates one additional thread.
concurrent::n_threaded_fifo_task_queue queue(1);
// Add tasks to queue, task is executed in created thread.
std::future<int> future_result = queue.push_with_result([] { return 4; });
// Blocks until task is completed.
int result = future_result.get();
// Executes task on the same thread as before.
std::future<int> second_future_result = queue.push_with_result([] { return 4; });
}
If you want to follow the Active Object approach here is an example using templates:
The WorkPackage and it's interface are just for storing functions of different return type in a vector (see later in the ActiveObject::async member function):
class IWorkPackage {
public:
virtual void execute() = 0;
virtual ~IWorkPackage() {
}
};
template <typename R>
class WorkPackage : public IWorkPackage{
private:
std::packaged_task<R()> task;
public:
WorkPackage(std::packaged_task<R()> t) : task(std::move(t)) {
}
void execute() final {
task();
}
std::future<R> get_future() {
return task.get_future();
}
};
Here's the ActiveObject class which expects your devices as a template. Furthermore it has a vector to store the method requests of the device and a thread to execute those methods one after another. Finally the async function is used to request a method call from the device:
template <typename Device>
class ActiveObject {
private:
Device servant;
std::thread worker;
std::vector<std::unique_ptr<IWorkPackage>> work_queue;
std::atomic<bool> done;
std::mutex queue_mutex;
std::condition_variable cv;
void worker_thread() {
while(done.load() == false) {
std::unique_ptr<IWorkPackage> wp;
{
std::unique_lock<std::mutex> lck {queue_mutex};
cv.wait(lck, [this] {return !work_queue.empty() || done.load() == true;});
if(done.load() == true) continue;
wp = std::move(work_queue.back());
work_queue.pop_back();
}
if(wp) wp->execute();
}
}
public:
ActiveObject(): done(false) {
worker = std::thread {&ActiveObject::worker_thread, this};
}
~ActiveObject() {
{
std::unique_lock<std::mutex> lck{queue_mutex};
done.store(true);
}
cv.notify_one();
worker.join();
}
template<typename R, typename ...Args, typename ...Params>
std::future<R> async(R (Device::*function)(Params...), Args... args) {
std::unique_ptr<WorkPackage<R>> wp {new WorkPackage<R> {std::packaged_task<R()> { std::bind(function, &servant, args...) }}};
std::future<R> fut = wp->get_future();
{
std::unique_lock<std::mutex> lck{queue_mutex};
work_queue.push_back(std::move(wp));
}
cv.notify_one();
return fut;
}
// In case you want to call some functions directly on the device
Device* operator->() {
return &servant;
}
};
You can use it as follows:
ActiveObject<QSerialPort> ao_serial_port;
// direct call:
ao_serial_port->setReadBufferSize(size);
//async call:
std::future<void> buf_future = ao_serial_port.async(&QSerialPort::setReadBufferSize, size);
std::future<Parity> parity_future = ao_serial_port.async(&QSerialPort::parity);
// Maybe do some other work here
buf_future.get(); // wait until calculations are ready
Parity p = parity_future.get(); // blocks if result not ready yet, i.e. if method has not finished execution yet
EDIT to answer the question in the comments: The AO is mainly a concurrency pattern for multiple reader/writer. As always, its use depends on the situation. And so this pattern is commonly used in distributed systems/network applications, for example when multiple clients request a service from a server. The clients benefit from the AO pattern as they are not blocked, when waiting for the server to answer.
One reason why this pattern is not used so often in fields other then network apps might be the thread overhead. When creating a thread for every active object results in a lot of threads and thus thread contention if the number of CPUs is low and many active objects are used at once.
I can only guess why people think it is a strange issue: As you already found out it does require some additional programming. Maybe that's the reason but I'm not sure.
But I think the pattern is also very useful for other reasons and uses. As for your example, where the main thread (and also other background threads) require a service from singletons, for example some devices or hardware interfaces, which are only availabale in a low number, slow in their computations and require concurrent access, without being blocked waiting for a result.
It's Qt. It's signal-slot mechanism is thread-aware. On your secondary (non-GUI) thread, create a QObject-derived class with an execute slot. Signals connected to this slot will marshal the event to that thread.
Note that this QObject can't be a child of a GUI object, since children need to live in their parents thread, and this object explicitly does not live in the GUI thread.
You can handle the result using existing std::promise logic, just like std::future does.
I want to implement a thread that can accept function pointers from a main thread and execute them serially. My idea was to use a struct that keeps the function pointer and its object and keep pushing it to a queue. This can be encapsulated in a class. The task thread can then pop from the queue and process it. I also need to synchronize it(so it doesnt block the main thread?), so I was thinking of using a semaphore. Although I have a decent idea of the structure of the program, I am having trouble coding this up, especially the threading and semaphore sync in C++11. It'd be great if someone can suggest an outline by which I can go about implementing this.
EDIT: The duplicate question answers the question about creating a thread pool. It looks like multiple threads are being created to do some work. I only need one thread that can queue function pointers and process them in the order they are received.
Check this code snippet, I have implemented without using a class though. See if it helps a bit. Conditional variable could be avoided here, but I want the reader thread to poll only when there is a signal from the writer so that CPU cycles in the reader won't be wasted.
#include <iostream>
#include <functional>
#include <mutex>
#include <thread>
#include <queue>
#include <chrono>
#include <condition_variable>
using namespace std;
typedef function<void(void)> task_t;
queue<task_t> tasks;
mutex mu;
condition_variable cv;
bool stop = false;
void writer()
{
while(!stop)
{
{
unique_lock<mutex> lock(mu);
task_t task = [](){ this_thread::sleep_for(chrono::milliseconds(100ms)); };
tasks.push(task);
cv.notify_one();
}
this_thread::sleep_for(chrono::milliseconds(500ms)); // writes every 500ms
}
}
void reader()
{
while(!stop)
{
unique_lock<mutex> lock(mu);
cv.wait(lock,[]() { return !stop;});
while( !tasks.empty() )
{
auto task = tasks.front();
tasks.pop();
lock.unlock();
task();
lock.lock();
}
}
}
int main()
{
thread writer_thread([]() { writer();} );
thread reader_thread([]() { reader();} );
this_thread::sleep_for(chrono::seconds(3s)); // main other task
stop = true;
writer_thread.join();
reader_thread.join();
}
Your problem has 2 parts. Storing the list of jobs and manipulating the jobs list in a threadsafe way.
For the first part, look into std::function, std::bind, and std::ref.
For the second part, this is similar to the producer/consumer problem. You can implement a semaphore using std::mutexand std::condition_variable.
There's a hint/outline. Now my full answer...
Step 1)
Store your function pointers in a queue of std::function.
std::queue<std::function<void()>>
Each element in the queue is a function that takes no arguments and returns void.
For functions that take arguments, use std::bind to bind the arguments.
void testfunc(int n);
...
int mynum = 5;
std::function<void()> f = std::bind(testfunction, mynum);
When f is invoked, i.e. f(), 5 will be passed as argument 1 to testfunc. std::bind copies mynum by value immediately.
You probably will want to be able to pass variables by reference as well. This is useful for getting results back from functions as well as passing in shared synchronization devices like semaphores and conditions. Use std::ref, the reference wrapper.
void testfunc2(int& n); // function takes n by ref
...
int a = 5;
std::function<void()> f = std::bind(testfunction, std::ref(a));
std::function and std::bind can work with any callables--functions, functors, or lambdas--which is pretty neat!
Step 2)
A worker thread dequeues while the queue is non-empty. Your code should look similar to the producer/consumer problem.
class AsyncWorker
{
...
public:
// called by main thread
AddJob(std::function<void()> f)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
private:
worker_main()
{
while(!m_exitCondition)
doJob();
}
void doJob()
{
std::function<void()> f;
{
std::unique_lock<std::mutex> lock(m_mutex);
while (m_numJobs == 0)
m_condition.wait(lock);
if (m_exitCondition)
return;
f = std::move(m_queue.front());
m_queue.pop();
--m_numJobs;
}
f();
}
...
Note 1: The synchronization code...with m_mutex, m_condition, and m_numJobs...is essentially what you have to use to implement a semaphore in C++'11. What I did here is more efficient than using a separate semaphore class because only 1 lock is locked. (A semaphore would have its own lock and you would still have to lock the shared queue).
Note 2: You can easily add additional worker threads.
Note 3: m_exitCondition in my example is an std::atomic<bool>
Actually setting up the AddJob function in a polymorphic way gets into C++'11 variadic templates and perfect forwarding...
class AsyncWorker
{
...
public:
// called by main thread
template <typename FUNCTOR, typename... ARGS>
AddJob(FUNCTOR&& functor, ARGS&&... args)
{
std::function<void()> f(std::bind(std::forward<FUNCTOR>(functor), std::forward<ARGS&&>(args)...));
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(std::move(f));
++m_numJobs;
}
m_condition.notify_one(); // It's good style to call notify_one when not holding the lock.
}
I think it may work if you just used pass-by-value instead of using the forwarding references, but I haven't tested this, while I know the perfect forwarding works great. Avoiding perfect forwarding may make the concept slightly less confusing but the code won't be much different...
Here is a nice working multi-thread code. It uses std::async :-
class C{ public: int d=35; };
class B{
public: C* c;
public: void test(){
std::vector<std::future<void>> cac;
for(int n=0;n<5;n++){
cac.push_back(
std::async(std::launch::async,[&](){
test2();
})
);
}
for(auto& ele : cac){
ele.get();
}
};
public: void test2(){
std::vector<std::future<void>> cac;
for(int n=0;n<5;n++){
cac.push_back(
std::async(std::launch::async,[&](){
int accu=0;
for(int i=0;i<10000;i++){
accu+=i;
}
std::cout<<accu<<" access c="<<c->d<<std::endl;
})
);
}
for(auto& ele : cac){
ele.get();
}
}
};
Here is the test case :-
int main(){
C c;
B b; b.c=&c;
b.test();
std::cout<<"end"<<std::endl;
}
It works, but if I change from std::async to use thread-pool library e.g.
Progschj's ThreadPool (https://github.com/progschj/ThreadPool/blob/master/ThreadPool.h)
ThreadPool pool(4);
...
pool.enqueue([&](){
test2();
})
vit-vit's ctpl (https://github.com/vit-vit/CTPL/blob/master/ctpl_stl.h)
ctpl::thread_pool pool(4);
...
pool.push([&](int threadId){
test2();
})
... I will encounter either access violation or freeze (presumably, dead lock).
Question
Does it mean I can't create a task from another task?
Which part of code is the cause of the restriction? How to overcome it?
Here are all 3 MCVE.
std::async (Coliru) , Progschj's ThreadPool (pastebin), ctpl (pastebin).
I have tried to dig into their library, but with my limited experience, I can't find the cause.
Clue
In real-case, the error tends to happen when amount of task > amount of thread (4).
Sometimes, it causes unrelated-library's thread to halt forever. (e.g. SDL keyboard listener.)
In a more complex program, Visual Studio sometimes catch this (B*) = 0x02.
(I guess the reference to this is removed after a-lambda-with-capture is used once in a loop; out-of-scope??)
Here is the most suspicious location in ThreadPool (both library are very similar):-
// add new work item to the pool
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if(stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){ (*task)(); });
}
condition.notify_one();
return res;
}
The deadlock comes because the tasks in the ThreadPool cannot be preempted. Hence if you recursively call the ThreadPool::enqueue method and afterwards wait for the result you end up in the deadlock because all the threads are used and cannot execute the newly enqueued tasks.
A little more detailed:
Let's go through your code step by step.
1. You call B::test() this function enqeues 5 tasks in the thread pool and later waits for their result, i.e. for them to finish, in ele.get().
2. The threads in the thread pool deque one of those tasks (enqued in step 1), which means if the amount of threads <= the amount of tasks, all of the threads execute B::test2(). Here again you enqueue 5 new tasks in the thread pool.
3. Now comes the critical point. Later in B::test2() you wait for the result of those tasks by ele.get(), which means the threads of the thread pool are blocked, until the tasks (the ones with the for loop) have been executed and their result was saved in the std::future. But as the threads of the thread pool are blocked, they cannot execute tasks any more. Hence the currently running tasks wait for the execution of the other tasks, which will never be executed because all the threads are blocked ==> deadlock.
Late answer, but I hope its useful. Some time ago I developed a small but effective threadpool library.
With little modifications, I have tested your use case and it seems to work great, so maybe you could give it a look.
Live demo. (Sorry for the size, I had to include all the library code inside to test it with your example)
I've been trying my luck on a small threadpool implementation.
However, after conceptualizing and implementing i've hit a brick wall.
I've confirmed that the worker threads ate starting up and sleeping correctly, also that they pick up and execute stored tasks correctly.
However, my program segfaults - i'm pretty sure its at promise.set_value.
Im not sure how i could provide a complete, verifiable example (given that i can hardly upload the whole code) but i'll include the segments
i believe to be relevant to this problem.
First off, workers are created like this:
worker = [this](){
while(true)
{
std::unique_lock<std::mutex> lock(mStatusMutex); //CV for status updates
mCV.wait(lock);
if(mStatus != Running) //If threadpool status does not imply running
break; //Break out of loop, ending thread in the process
else //If threadpool is in running state
{
lock.unlock(); //Unlock state
while(true) //Loop until no tasks are left
{
mTasksMutex.lock(); //Lock task queue
if(mTasks.empty()) //IF no tasks left, break out of loop and return to waiting
{
mTasksMutex.unlock();
break;
}
else //Else, retrieve a task, unlock the task queue and execute the task
{
std::function<void()> task = mTasks.front();
mTasks.pop();
mTasksMutex.unlock();
task(); //Execute task
}
}
}
}
};
And then started and stored into a std::vector<std::thread> like this:
std::thread tWorker(worker);
mWorkers.push_back(std::move(tWorker));
Now, the tricky part i believe to be the following is when adding/executing tasks to the task queue, which is a std::queue<std::function<void()>>.
The following two functions are relevant here:
template<typename RT>
inline std::future<RT> queueTask(std::function<RT()> _task, bool _execute = false)
{
std::promise<RT> promise;
std::function<void()> func([&_task, &promise]() -> RT {
RT val = _task();
promise.set_value(val);
});
mTasksMutex.lock();
mTasks.emplace(func);
mTasksMutex.unlock();
if(_execute) flush();
return promise.get_future();
}
inline void flush()
{
mCV.notify_all();
}
Is there anything principally wrong with this approach?
For anyone who believes this to be a bad question, feel free to tell me how i can improve it.
Full code is hosted on my github repo.
The main problem is that the promise is already dead. When queueTask is done, the promise is destroyed, and the task now just has a dangling reference. The task must share ownership of the promise in order for it to live long enough to fulfill it.
The same is true of the underlying std::function object _task, since you're capturing it by reference.
You're using std::function, which requires copyable objects, hence... shared_ptr:
template<typename RT>
inline std::future<RT> queueTask(std::function<RT()> _task, bool _execute = false)
{
auto promise = std::make_shared<std::promise<RT>>();
std::function<void()> func([promise, task=std::move(_task)]{
RT val = _task();
promise->set_value(val);
});
{
std::lock_guard<std::mutex> lk(mTasksMutex); // NB: no manual lock()/unlock()!!
mTasks.emplace(func);
}
if(_execute) flush();
return promise->get_future();
}
Consider std::packaged_task instead.
I try to give a std::bind to another existing thread currently waiting in a condition_variable. I really want to keep this other thread alive and not creating another one.
But I don't know how to give this std::bind to the other thread, due to the fact that everything is decided at compile-time.
I know that boost thread pool manage that, and I really wonder how and I'd like doing it without boost.
Here is some pseudo-code
class Exec
{
template<typename Func, typename... Args>
auto call(Func func, Args... args)
{
sendWork(std::bind(func, this->someMemberClass, args...)); // Async
return getResults(); // Waiting til get results
}
void waitThread()
{
//Thread waiting
// Will do the std::bind sent at sendWork
}
}
Has someone any idea?
Thank you for your time!
As mentioned in the commentaries, the only current way to pass a generic function to another thread is by using std::function<void()> which forbid any return type, but grants the ability to specify any parameters and number of parameters, in order to return results, you'll have to think about callbacks.