I'm trying to implement this Thread Pool with classes in C++.
Since now I was confident to have understand how classes work but now I'm getting mad.
I have 2 files
"JobScheduler.h" and "JobScheduler.cpp"
JobScheduler.h
class JobScheduler {
int thread_id;
std::vector<std::thread> pool;
std::mutex m1;
int set_id();
public:
JobScheduler();
~JobScheduler();
void Start();
};
JobScheduler.cpp
int id = 0;
std::mutex m;
JobScheduler::JobScheduler() {...}
JobScheduler::~JobScheduler() {...}
int JobScheduler::set_id() {
m1.lock();
int tmp_id = thread_id;
thread_id++;
std::cout << "id = " << tmp_id << "\n";
m1.unlock();
return tmp_id;;
}
int set_id_02(){
m.lock();
int tmp_id = id;
id++;
std::cout << "id = " << tmp_id << "\n";
m.unlock();
return tmp_id;
}
void JobScheduler::Start(){
// THIS DOESN'T WORK
/*
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
pool.emplace_back(std::thread(std::packaged_task<void()>(JobScheduler::set_id))); // <--- error
}
... // print something and join threads
*/
// MANY THREADS - NO CLASS METHOD AS FUNCTION AND GLOBAL CPP VARIABLE - WORK
/*
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
pool.emplace_back(std::thread(std::packaged_task<int()>(set_id_02)));
}
... // print something and join threads
*/
}
now if I use a function defined in .cpp it works fine but if I try to use a function I defined in the class it doesn't work but I need to be able to access Class variables.
So I have a lot of doubts:
1) why this doesn't work, what am I getting wrong?
2) it's ok to create a std::package_task like I do in the for? Or should I do something like
std::pakaged_task<int()> main_task(set_id);
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
pool.emplace_back(std::thread(main_task));
}
3) in both cases how can I access the future of the task I created?
1) It's not working because you are creating the packaged task wrongly.
Since you are trying to use a member function you have to specify which object is going to be used to call those functions so you can try different approaches
Bind the object with the member function
Use a lambda as a proxy
std::packaged_task<int()>(std::bind(&JobScheduler::set_id, this))
std::packaged_task<int()>([this]{ return set_id(); })
For the second function is enough to just pass the function since it's a "free" function
std::packaged_task<int()>(set_id_02);
2) See above
3) In order to access the results of your packaged_task you must store its future
std::vector<std::future<int>> results;
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
auto task = std::packaged_task<int()>([this]{ return set_id(); });
results.emplace_back(task.get_future());
pool.emplace_back(std::thread(std::move(task)));
}
//Access results
for (auto& f : results) {
cout << f.get() << endl;
}
As you rightly say, the problem is that you have to provide the object on which you want to call the member function. I see two solutions for that
// 1st wrap in a lambda
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
pool.emplace_back(std::thread(std::packaged_task<void()>([this](){this->set_id();})));
}
// 2nd Use std::mem_fn and std::bind
for(unsigned int i = 0; i < std::thread::hardware_concurrency(); i++){
pool.emplace_back(std::thread(std::packaged_task<void()>(std::bind(std::mem_fn(&JobScheduler::set_id), *this))));
}
The first one should be clear, I think. In the second, std::mem_fn creates a function f such that f(object) does object.set_id() and std::bind creates a function g such that g() does f(this).
I prefer the first solution. It is one of many cases where lambdas are much simpler than using bind.
Related
I'm trying to write a program that concurrently add and removes items from a "storehouse". I have a "Monitor" class that handles the "storehouse" operations:
class Monitor
{
private:
mutex m;
condition_variable cv;
vector<Storage> S;
int counter = 0;
bool busy = false;;
public:
void add(Computer c, int index) {
unique_lock <mutex> lock(m);
if (busy)
cout << "Thread " << index << ": waiting for !busy " << endl;
cv.wait(lock, [&] { return !busy; });
busy = true;
cout << "Thread " << index << ": Request: add " << c.CPUFrequency << endl;
for (int i = 0; i < counter; i++) {
if (S[i].f == c.CPUFrequency) {
S[i].n++;
busy = false; cv.notify_one();
return;
}
}
Storage s;
s.f = c.CPUFrequency;
s.n = 1;
// put the new item in a sorted position
S.push_back(s);
counter++;
busy = false; cv.notify_one();
}
}
The threads are created like this:
void doThreadStuff(vector<Computer> P, vector <Storage> R, Monitor &S)
{
int Pcount = P.size();
vector<thread> myThreads;
myThreads.reserve(Pcount);
for (atomic<size_t> i = 0; i < Pcount; i++)
{
int index = i;
Computer c = P[index];
myThreads.emplace_back([&] { S.add(c, index); });
}
for (size_t i = 0; i < Pcount; i++)
{
myThreads[i].join();
}
// printing results
}
Running the program produced the following results:
I'm familiar with race conditions, but this doesn't look like one to me. My bet would be on something reference related, because in the results we can see that for every "missing thread" (threads 1, 3, 10, 25) I get "duplicate threads" (threads 2, 9, 24, 28).
I have tried to create local variables in functions and loops but it changed nothing.
I have heard about threads sharing memory regions, but my previous work should have produced similar results, so I don't think that's the case here, but feel free to prove me wrong.
I'm using Visual Studio 2017
Here you catch local variables by reference in a loop, they will be destroyed in every turn, causing undefined behavior:
for (atomic<size_t> i = 0; i < Pcount; i++)
{
int index = i;
Computer c = P[index];
myThreads.emplace_back([&] { S.add(c, index); });
}
You should catch index and c by value:
myThreads.emplace_back([&S, index, c] { S.add(c, index); });
Another approach would be to pass S, i and c as arguments instead of capturing them by defining the following non-capturing lambda, th_func:
auto th_func = [](Monitor &S, int index, Computer c){ S.add(c, index); };
This way you have to explicitly wrap the arguments that must be passed by reference to the thread's callable object with std::reference_wrapper by means of the function template std::ref(). In your case, only S:
for (atomic<size_t> i = 0; i < Pcount; i++) {
int index = i;
Computer c = P[index];
myThreads.emplace_back(th_func, std::ref(S), index, c);
}
Failing to wrap with std::reference_wrapper the arguments that must be passed by reference will result in a compile-time error. That is, the following won't compile:
myThreads.emplace_back(th_func, S, index, c); // <-- it should be std::ref(S)
See also this question.
I would like to know which one would be the best way of using values created inside a loop, outside of that loop. I have for example the function:
void Loop(int a)
{
// recursion loop execution
for ( int i = 0; i < 10; i++ )
{
int new_a = a + i;
}
}
I would like to use that "new_a" as it is being "looped" in another function which is plotting a graph and only needs the "yAxe" value. Like that:
int main ()
{
int a = 5;
plot (x,Loop(int a);
}
I know I could create an array with the values of the loop but I wouldn't like to store them and for big plottings would be too much memory.
Any local variable will be destroyed when the scope of them be finished. For example, in your code new_a will be destroyed when the for loop is finished, and the a is destroyed when the function be finished. I mean if you care about memory, don't be worry.
If I understand you correctly, you want to call Loop multiple times (like e.g. Loop(a)) and each call you should get the next "iteration" of the loop?
That would have been easy if C++ had continuations which it doesn't. Instead it can be emulated by using classes and objects and operator overloading.
For example:
class LoopClass
{
public:
LoopClass(int initial_value = 0)
: current_value{initial_value}
{
}
int operator()(int a)
{
return a + current_value++;
}
private:
int current_value;
};
It can be used as such:
LoopClass Loop; // The value initialized with zero
int a = 5;
std::cout << "First call : " << Loop(a) << '\n';
std::cout << "Second call: " << Loop(a) << '\n';
The above code, if put into a program, should print
First call : 5
Second call: 6
I'm trying to stop multiple worker threads using a std::atomic_flag. Starting from Issue using std::atomic_flag with worker thread the following works:
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
std::atomic_flag continueFlag;
std::thread t;
void work()
{
while (continueFlag.test_and_set(std::memory_order_relaxed)) {
std::cout << "work ";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void start()
{
continueFlag.test_and_set(std::memory_order_relaxed);
t = std::thread(&work);
}
void stop()
{
continueFlag.clear(std::memory_order_relaxed);
t.join();
}
int main()
{
std::cout << "Start" << std::endl;
start();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Stop" << std::endl;
stop();
std::cout << "Stopped." << std::endl;
return 0;
}
Trying to rewrite into multiple worker threads:
#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>
#include <memory>
struct thread_data {
std::atomic_flag continueFlag;
std::thread thread;
};
std::vector<thread_data> threads;
void work(int threadNum, std::atomic_flag &continueFlag)
{
while (continueFlag.test_and_set(std::memory_order_relaxed)) {
std::cout << "work" << threadNum << " ";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void start()
{
const unsigned int numThreads = 2;
for (int i = 0; i < numThreads; i++) {
////////////////////////////////////////////////////////////////////
//PROBLEM SECTOR
////////////////////////////////////////////////////////////////////
thread_data td;
td.continueFlag.test_and_set(std::memory_order_relaxed);
td.thread = std::thread(&work, i, td.continueFlag);
threads.push_back(std::move(td));
////////////////////////////////////////////////////////////////////
//PROBLEM SECTOR
////////////////////////////////////////////////////////////////////
}
}
void stop()
{
//Flag stop
for (auto &data : threads) {
data.continueFlag.clear(std::memory_order_relaxed);
}
//Join
for (auto &data : threads) {
data.thread.join();
}
threads.clear();
}
int main()
{
std::cout << "Start" << std::endl;
start();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Stop" << std::endl;
stop();
std::cout << "Stopped." << std::endl;
return 0;
}
My issue is "Problem Sector" in above. Namely creating the threads. I cannot wrap my head around how to instantiate the threads and passing the variables to the work thread.
The error right now is referencing this line threads.push_back(std::move(td)); with error Error C2280 'thread_data::thread_data(const thread_data &)': attempting to reference a deleted function.
Trying to use unique_ptr like this:
auto td = std::make_unique<thread_data>();
td->continueFlag.test_and_set(std::memory_order_relaxed);
td->thread = std::thread(&work, i, td->continueFlag);
threads.push_back(std::move(td));
Gives error std::atomic_flag::atomic_flag(const std::atomic_flag &)': attempting to reference a deleted function at line td->thread = std::thread(&work, i, td->continueFlag);. Am I fundamentally misunderstanding the use of std::atomic_flag? Is it really both immovable and uncopyable?
Your first approach was actually closer to the truth. The problem is that it passed a reference to an object within the local for loop scope to each thread, as a parameter. But, of course, once the loop iteration ended, that object went out of scope and got destroyed, leaving each thread with a reference to a destroyed object, resulting in undefined behavior.
Nobody cared about the fact that you moved the object into the std::vector, after creating the thread. The thread received a reference to a locally-scoped object, and that's all it knew. End of story.
Moving the object into the vector first, and then passing to each thread a reference to the object in the std::vector will not work either. As soon as the vector internally reallocates, as part of its natural growth, you'll be in the same pickle.
What needs to happen is to have the entire threads array created first, before actually starting any std::threads. If the RAII principle is religiously followed, that means nothing more than a simple call to std::vector::resize().
Then, in a second loop, iterate over the fully-cooked threads array, and go and spawn off a std::thread for each element in the array.
I was almost there with my unique_ptr solution. I just needed to pass the call as a std::ref() as such:
std::vector<std::unique_ptr<thread_data>> threads;
void start()
{
const unsigned int numThreads = 2;
for (int i = 0; i < numThreads; i++) {
auto td = std::make_unique<thread_data>();
td->continueFlag.test_and_set(std::memory_order_relaxed);
td->thread = std::thread(&work, i, std::ref(td->continueFlag));
threads.push_back(std::move(td));
}
}
However, inspired by Sam above I also figured a non-pointer way:
std::vector<thread_data> threads;
void start()
{
const unsigned int numThreads = 2;
//create new vector, resize doesn't work as it tries to assign/copy which atomic_flag
//does not support
threads = std::vector<thread_data>(numThreads);
for (int i = 0; i < numThreads; i++) {
auto& t = threads.at(i);
t.continueFlag.test_and_set(std::memory_order_relaxed);
t.thread = std::thread(&work, i, std::ref(t.continueFlag));
}
}
With the below code, I would like to place(push_back) the threads in a vector and launch the thread after every pop operation from vector.
#include <iostream>
#include <thread>
#include <algorithm>
int main() {
std::vector<std::thread> workers;
for(int i = 0; i < 10; ++i){
workers.push_back(std::thread([](){
std::cout << "Hi from thread\n";
}));
}
std::cout << "Hi from main!\n";
std::for_each(workers.begin(), workers.end(), [](std::thread &th){
th.join();
});
return 0;
}
But push_back() instruction does not actually convey that we are storing threads to launch it later. Because calling a constructor of class std::thread immediately launches thread.
In java, launch of thread can happen by placing in Queue(say) and dequeue it something like this:
-> searchQueue.enqueue( new SearchTask( record, this ) );
-> return searchQueue.size () > 0 ? (Runnable) searchQueue.removeFirst () : null ;
Because in java, thread gets launched after you invoke start() method of class Thread.
So, How do i perform similar operation in C++11?
You can store non-running threads plus the functions they will later run together:
typedef std::pair<std::thread, std::function<void()>> ThreadAndFunction;
std::vector<ThreadAndFunction> workers;
for(int i = 0; i < 10; ++i){
ThreadAndFunction tf;
workers.emplace_back(std::thread(), [](){
std::cout << "Hi from thread\n";
});
}
Then later, activate the threads using the functions:
for(int i = 0; i < 10; ++i){
workers[i].first = std::thread(workers[i].second);
}
However, I don't think you're gaining much here. You could just store the functions without the empty threads at first, and create a vector of threads later.
I'm trying to create an array of threads and give each of them a function but not working
Reader *readers = new Reader[10];
thread *ts = new thread[10];
for (int i = 0; i<10; i++){
readers[i].setAll(q, "t" + i);
ts[i] = thread(readers[i].run); //Error: "cannot be referenced. its a deleted function"
}
Run function:
void Reader::run(){
log(this->source);
log.log("starting");
while (flag){
this->m = this->q.get(this->source);
log.log("retrieved " + m.toString());
if (m.getData().compare("stop") && m.getTarget().compare(this->source))
{
log.log("stopping");
this->setFlag(false);//stop the current thread if the message is "stop"
}
else{
if (!m.getTarget().compare(source)){//if the message isnt from the current thread then put the message back
string dest = m.getSource();
m.setSource(this->source);
log.log("putting back [" + dest + "->" + m.getTarget() + ":" + " " + m.getData() + "] as " + m.toString());
q.put(m);
log.log("done putting back " + m.toString());
}
}
}
}
I'm actually trying to do the following code:
thread t0(readers[0].run);
thread t1(readers[1].run);
etc...
but it also gives me the same error seen below:
If you're using c++11 you might want to take advantage of the nice memory management and binding features:
(edit: updated code in response to comments)
#include <iostream>
#include <thread>
#include <memory>
#include <vector>
using namespace std;
struct runner
{
void run() {
cout << "hello" << endl;
}
};
int main()
{
vector<unique_ptr<runner>> runners;
for(size_t i = 0 ; i < 10 ; ++i) {
runners.emplace_back(new runner);
}
vector<thread> threads;
for(const auto& r : runners) {
threads.emplace_back(&runner::run, r.get());
}
for(auto& t : threads) {
t.join();
}
return 0;
}
While readers[i].run looks like it should bind an object to a member function to make a callable object, sadly it doesn't. Instead, you need to pass a pointer to the member function and a pointer (or reference wrapper) to the object as separate arguments:
thread(&Reader::run, &readers[i]); // or std::ref(readers[i])
or you might find it nicer to wrap the function call in a lambda:
thread([=]{readers[i].run();})