I am trying to create a ThreadPool class which has a constructor like this
ThreadPool(size_t numberOfThreads)
: workerThreads(numberOfThreads) {
workerThreads.reserve(numberOfThreads);
for(int i =0; i < numberOfThreads; i++) {
workerThreads.emplace_back(std::thread(&ThreadPool::doJob, this));
}
}
This fails to compile for me and throws following error
error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/thread:352:5: note: in instantiation of function template specialization
'std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void
(ThreadPool::*)(std::__1::function<void (char *, std::__1::list<std::__1::basic_string<char>,
std::__1::allocator<std::__1::basic_string<char> > > *)>), ThreadPool *, 2>' requested here
__thread_execute(*__p, _Index());
As per other answers to similar question I also tried doing this
workerThreads.emplace_back(std::thread(&ThreadPool::doJob, std::ref(*this)));
This is reproducing same issue as well. I am compiling my code with clang c++14 on macos
Here is complete program where this reproduces
class ThreadPool {
public:
ThreadPool(size_t numberOfThreads)
: workerThreads(numberOfThreads) {
for(int i =0; i < numberOfThreads; i++) {
workerThreads[i] = std::make_shared<std::thread>(std::thread(&ThreadPool::doJob, this));
}
}
ThreadPool(const ThreadPool& tp) {
workerThreads = tp.workerThreads;
jobQueue = tp.jobQueue;
}
std::function<void(char*, std::list<std::string>*)> getNextJob() {
if(!jobQueue.empty()) {
std::function<void(char*, std::list<std::string>*)> job = jobQueue.front();
jobQueue.pop_front();
return job;
}
throw std::runtime_error("No jobs to process, thread finished");
}
void addWork(std::function<void(char*, std::list<std::string>*)> job) {
lockListMutex.lock();
jobQueue.push_back(job);
lockListMutex.unlock();
}
private:
// performs actual work
void doJob(std::function<void(char*, std::list<std::string>*)> job) {
try {
lockListMutex.lock();
getNextJob();
lockListMutex.unlock();
} catch (std::runtime_error &e) {
}
}
// a vector containing worker threads
std::vector<std::shared_ptr<std::thread>> workerThreads;
// a queue for jobs
std::list<std::function<void(char*, std::list<std::string>*)>> jobQueue;
// a mutex for synchronized insertion and deletion from list
std::mutex lockListMutex;
};
int main(int argc, char *argv[]) {
int numThreads = 1;
ThreadPool* pool = new ThreadPool(numThreads);
}
Since your doJob member function has a parameter job of type std::function<void(char*, std::list<std::string>*)>, you need to provide a corresponding argument when this function is called. Therefore, calling of this function in a new thread this way is invalid:
std::thread(&ThreadPool::doJob, this) // no argument for job passed
You either need to provide an argument, or, since the jobs should be likely dequeued from jobQueue, remove the job parameter from doJob:
void doJob()
{
... // dequeue job from jobQueue and execute it
Related
My program has a class similar to the following:
class IOWorker {
std::thread thread_;
boost::asio::io_service ios_;
boost::optional<boost::asio::io_service::work> work_;
Callback callback_;
static thread_local IOWorker* this_thread_worker_;
public:
IOWorker(Callback cb);
~IOWorker();
// IO worker threads will call this to fetch their instance
static IOWorker* getIOWorkerInstance (void) {
return this_thread_worker_;
}
};
IOWorker::IOWorker (Callback cb) : callback_{std::move(cb)}
{
work_ = boost::in_place(boost::ref(ios_));
thread_ = std::thread{[this] () {
this_thread_worker_ = this;
ios_.run();
}};
}
Main thread calls the following function to create IOWorker instances/threads:
std::vector<IOWorker> startIOWorkers(Callback cb)
{
std::vector<IOWorker> launched_workers;
launched_workers.reserve(10);
for (int i = 0; i < 10; ++i) {
launched_workers.emplace_back(cb);
}
return launched_workers;
}
But the compilation fails with the following error (pointing to _Up):
error: call to implicitly-deleted copy constructor of 'IOWorker'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
Not sure what changes I need to make in the above class to resolve this error.
I want this class (objects) to be non-copyable, but can be movable.
I have a class:
class IOWorker {
std::thread thread_;
boost::asio::io_service ios_;
boost::optional<boost::asio::io_service::work> work_;
Callback callback_;
// Map of thread::id and this class' instance
typedef std::map<std::thread::id, IOWorker *> IOWorkerThreadMap;
static IOWorkerThreadMap iOWorkerThreadMap;
public:
IOWorker(Callback cb);
~IOWorker();
std::thread::id getThreadId() {
return thread_.get_id();
}
// IO worker threads will call this to fetch their instance
static IOWorker* getIOWorkerInstance (void) {
auto it = iOWorkerThreadMap.find(std::this_thread::get_id());
if (it == iOWorkerThreadMap.end()) {
return nullptr;
}
return (it->second);
}
};
IOWorker::IOWorker (Callback cb) : callback_{cb}
{
work_ = boost::in_place(boost::ref(ios_));
thread_ = std::thread{[this] () {
ios_.run();
}
};
}
In a function executed by the main thread, I'm creating 10 instances of this class and inserting these into the map where thread::id is key and class instance is value.
I'm accessing this map from all the worker threads to fetch their respective class instance by looking up their thread::id in the map. The main thread accesses these instances too, to call some methods, post jobs on ios_, etc.
void startIOWorkers (Callback cb)
{
for (int i = 0; i < 10; ++i) {
IOWorker *iow = new IOWorker{cb};
std::thread::id threadId = iow->getThreadId();
IOWorkerThreadMap.insert(std::make_pair(threadId, iow));
}
}
My question is for below line:
IOWorkerThreadMap.insert(std::make_pair(threadId, iow));
My understanding (could be wrong!) is that iow and threadId in above function, will be "copied" while I'm inserting them in the map and two copies of them will exist.
I want to avoid that, therefore, I would like to know what are the better ways of having a map of thread::id and class instance in this case?
This seems way more complicated than it has to be.
If, as it appears to be the case, you only need to access the map at from thread::this_thread, the language already has a map<thread_id, T> built right in: thread_local.
class IOWorker {
std::thread thread_;
boost::asio::io_service ios_;
boost::optional<boost::asio::io_service::work> work_;
Callback callback_;
static thread_local IOWorker* this_thread_worker_;
public:
IOWorker(Callback cb);
~IOWorker();
// IO worker threads will call this to fetch their instance
static IOWorker* getIOWorkerInstance (void) {
return this_thread_worker_;
}
};
IOWorker::IOWorker (Callback cb) : callback_{std::move(cb)}
{
work_ = boost::in_place(boost::ref(ios_));
thread_ = std::thread{[this] () {
this_thread_worker_ = this;
ios_.run();
};
}
std::vector<IOWorker> startIOWorkers(Callback cb)
{
std::vector<IOWorker> launched_workers;
launched_workers.reserve(10);
for (int i = 0; i < 10; ++i) {
launched_workers.emplace_back(cb);
}
return launched_workers;
}
I've read various answer on SO and still didn't understood how I should make an object method to be callable in this case:
Considering:
Class A
{
void generator(void)
{
int i = 1;
while(1)
{
if(i == 1)
{
one(/***/);//Should be a flag
i = 2;
}
else
{
two(/**/);//Should be a flag
i = 1;
}
}
}
template <typename CallbackFunction>
void one(CallbackFunction&& func)
{
}
template <typename CallbackFunction>
void two(CallbackFunction&& func)
{
}
A()
{
std::thread t(&A::generator, this);
t.detach();
}
};
and a simple main file:
void pOne(/**/)
{
std::cout<<"1"<<std::endl;
}
void pTwo(/**/)
{
std::cout<<"2"<<std::endl;
}
A myA;
A.One(pOne);
A.Two(pTwo);
int main(int argc, char** argv)
{
while(1){}
}
Here are where I'm at:
generator() should update a flag, and both one() & two() should poll on that flag & loop forever.
One() (two() also) should have a function pointer as parameters and if necessary other parameters, pOne() should have the same parameters except the function pointer.
So my questions are:
1) Is my understanding correct?
2) Is there a clean way to make generator() to start one() or two() ? (flags, semaphore, mutex, or anything that is a standard way to do it)
3) Assuming that the code was working, is it behaving as I expect ? i.e. printing 1 and 2?
if it matters, I'm on ubuntu
Disclaimer 1: Like everyone else, I'm interpreting the question as:
-> You need an event handler
-> You want callback methods on those events
And the only reason I think that is because I helped you on a i2c handler sequence before.
Also, there are better logic than this, its provided following your stubs "rules".
You mentioned that you are on Ubuntu, so you will be lacking windows event system.
Disclaimer 2:
1- To avoid going to deep I'm going to use a simple way to handle events.
2- Code is untested & provided for logic only
class Handler
{
private:
std::mutex event_one;
event_one.lock();
void stubEventGenerator(void)
{
for(;;)
{
if(!event_one.try_lock())
{
event_one.unlock();
}
sleep(15); //you had a sleep so I added one
}
}
template <typename CallbackFunction>
void One__(CallbackFunction && func)
{
while(1)
{
event_one.lock();
func();
}
}
public:
Handler()
{
std::thread H(&Handler::stubEventGenerator, this);
}
~Handler()
{
//clean threads, etc
//this should really have a quit handler
}
template <typename CallbackFunction>
void One(CallbackFunction && func) //I think you have it right, still I'm not 100% sure
{
std::thread One_thread(&Handler::One__, this, func); //same here
}
};
Some points:
One() as to be a wrapper for the thread calling One__() if you want it to be non-blocking.
mutex can be a simple way to handle events as long as the same event doesn't occur during its previous occurence (you are free to use a better/more suitable tool for your use case, or use boost:: only if necessary)
Prototype of One() & One__() are probably wrong, that's some research for you.
Finally: How it works:
std::mutex.lock() is blocking as long as it can't lock the mutex, thus One__ will wait as long as your event generator won't unlock it.
Once unlock One__ will execute your std::function & wait for the event (mutex) to be raised (unlock) again.
far from a perfect answer, but lack of time, and not being able to put that in a comment made me post it, will edit later
With whatever limited information you provided this code can be made compilable in following manner:
#include <iostream>
#include <thread>
typedef void(*fptr)();
void pOne(/**/)
{
std::cout<<"1"<<std::endl;
}
void pTwo(/**/)
{
std::cout<<"2"<<std::endl;
}
class A
{
public:
void generator(void)
{
int i = 1;
while(1)
{
if(i == 1)
{
fptr func = pOne;
one(func);//Should be a flag
i = 2;
}
else
{
fptr func = pTwo;
two(func);//Should be a flag
i = 1;
}
}
}
template <typename CallbackFunction>
void one(CallbackFunction&& func)
{
func();
}
template <typename CallbackFunction>
void two(CallbackFunction&& func)
{
func();
}
A()
{
std::thread t(&A::generator, this);
t.detach();
}
};
int main()
{
A myA;
while(1)
{
}
return 0;
}
If you want that one and two should accept any type/number of arguments then pass second argument as variadic template.Also I could not understand why you want one and two to be called from main as your generator function is for this purpose only and this generator function is called from thread which is detached in class constructor
I need to spawn class object. For example:
class Worker {
Worker(int arg1, Object *obj);
void workLoop() { while(true) { ... } }
}
And I need spawn in loop threads with creating objects. When I do this "static", it works:
thread th1(&Worker::workLoop, Worker(args...));
thread th2(&Worker::workLoop, Worker(other args...));
But I can't spawn this in loop. I tried:
for (...) {
thread th(&Worker::workLoop, Worker(...));
threadsVector.push_back(std::move(th));
}
...but only first thread works.
Also, I have in Worker class this:
std::thread spawn() {
return std::thread(&Worker::workLoop, this);
}
I don't know how do this and why loop can't spawn my threads correctly.
try this
class Worker{
Worker(int arg, Object *obj)
void workLoop() { while(true) { ... } }
}; // do not forget the semicolon
....
vector<thread> pool;
auto func = [](Worker w){
w.workLoop();
};
// example with thread
for (int i = 0; i < 5; ++i)
pool.push_back(thread(func, Worker(5, obj)));
for (int i = 0; i < pool.size(); ++i)
pool[i].join();
// example
create a lambda expression that takes in a worker object and calls the workLoop method inside
then you can pass the lambda as an object and pass it an argument inside the thread constructor
I just created my Thread Pool for game server, but i got one error in compiling what i didn't know how to fix.
Error :
Connection/CConnection.cpp: In lambda function:
Connection/CConnection.cpp:62:6: error: 'this' was not captured for
this lambda function
Thread Pool declaration :
class Worker {
public:
Worker(ThreadPool &s) : pool(s) { }
void operator()();
private:
ThreadPool &pool;
};
// the actual thread pool
class ThreadPool {
public:
ThreadPool(size_t);
template<class F>
void enqueue(F f);
~ThreadPool();
private:
// need to keep track of threads so we can join them
std::vector< std::unique_ptr<boost::thread> > workers;
// the io_service we are wrapping
boost::asio::io_service service;
boost::asio::io_service::work working;
friend class Worker;
};
template<class F>
void ThreadPool::enqueue(F f)
{
service.post(f);
}
Function what use it :
void CConnection::handle()
{
int i = 0;
ThreadPool pool(4);
pool.enqueue([i]
{
char * databuffer;
databuffer = new char[16];
for(int i = 0;i<16;i++)
{
databuffer[i] = 0x00;
}
databuffer[0] = 16;
databuffer[4] = 1;
databuffer[8] = 1;
databuffer[12] = 1;
asynchronousSend(databuffer, 16);
});
}
Can someone tell me where, and what is problem ?
My guess is that asynchronousSend is a function in the CConnection class. To call function in object you have to capture this:
pool.enqueue([this] { ... });
As you see I've removed the capture of i as it's not needed, since you declare a local i inside the lambda.