Array of Threads - c++

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();})

Related

Threads with Classes and std::packaged_task

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.

Displaying results as soon as they are ready with std::async

I'm trying to discover asynchronous programming in C++. Here's a toy example I've been using:
#include <iostream>
#include <future>
#include <vector>
#include <chrono>
#include <thread>
#include <random>
// For simplicity
using namespace std;
int called_from_async(int m, int n)
{
this_thread::sleep_for(chrono::milliseconds(rand() % 1000));
return m * n;
}
void test()
{
int m = 12;
int n = 42;
vector<future<int>> results;
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
results.push_back(async(launch::async, called_from_async, i, j));
}
}
for(auto& f : results)
{
cout << f.get() << endl;
}
}
Now, the example is not really interesting, but it raises a question that is, to me, interesting. Let's say I want to display results as they "arrive" (I don't know what will be ready first, since the delay is random), how should I do it?
What I'm doing here is obviously wrong, since I wait for all the tasks in the order in which I created them - so I'll wait for the first to finish even if it's longer than the others.
I thought about the following idea: for each future, using wait_for on a small time and if it's ready, display the value. But I feel weird doing that:
while (any_of(results.begin(), results.end(), [](const future<int>& f){
return f.wait_for(chrono::seconds(0)) != future_status::ready;
}))
{
cout << "Loop" << endl;
for(auto& f : results)
{
auto result = f.wait_for(std::chrono::milliseconds(20));
if (result == future_status::ready)
cout << f.get() << endl;
}
}
This brings another issue: we'd call get several times on some futures, which is illegal:
terminate called after throwing an instance of 'std::future_error' what(): std::future_error: No associated state
So I don't really know what to do here, please suggest!
Use valid() to skip the futures for which you have already called get().
bool all_ready;
do {
all_ready = true;
for(auto& f : results) {
if (f.valid()) {
auto result = f.wait_for(std::chrono::milliseconds(20));
if (result == future_status::ready) {
cout << f.get() << endl;
}
else {
all_ready = false;
}
}
}
}
while (!all_ready);

Pass a vector of custom structs by reference to a boost::compute closure or function

I'm somewhat new to opencl and am trying to learn to use boost::compute properly. Consider the following code:
#include <iostream>
#include <vector>
#include <boost/compute.hpp>
const cl_int cell_U_size{ 4 };
#pragma pack (push,1)
struct Cell
{
cl_double U[cell_U_size];
};
#pragma pack (pop)
BOOST_COMPUTE_ADAPT_STRUCT(Cell, Cell, (U));
int main(int argc, char* argv[])
{
using namespace boost;
auto device = compute::system::default_device();
auto context = compute::context(device);
auto queue = compute::command_queue(context, device);
std::vector<Cell> host_Cells;
host_Cells.reserve(10);
for (auto j = 0; j < host_Cells.capacity(); ++j) {
host_Cells.emplace_back(Cell());
for (auto i = 0; i < cell_U_size; ++i) {
host_Cells.back().U[i] = static_cast<cl_double>(i+j);
}
}
std::cout << "Before:\n";
for (auto const& hc : host_Cells) {
for (auto const& u : hc.U)
std::cout << " " << u;
std::cout << "\n";
}
compute::vector<Cell> device_Cells(host_Cells.size(), context);
auto f = compute::copy_async(host_Cells.begin(), host_Cells.end(), device_Cells.begin(), queue);
try {
BOOST_COMPUTE_CLOSURE(Cell, Step1, (Cell cell), (cell_U_size), {
for (int i = 0; i < cell_U_size; ++i) {
cell.U[i] += 1.0;
}
return cell;
});
f.wait(); // Wait for data to finish being copied
compute::transform(device_Cells.begin(), device_Cells.end(), device_Cells.begin(), Step1, queue);
//BOOST_COMPUTE_CLOSURE(void, Step2, (Cell &cell), (cell_U_size), {
// for (int i = 0; i < cell_U_size; ++i) {
// cell.U[i] += 1.0;
// }
//});
//compute::for_each(device_Cells.begin(), device_Cells.end(), Step2, queue);
compute::copy(device_Cells.begin(), device_Cells.end(), host_Cells.begin(), queue);
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
throw;
}
std::cout << "After:\n";
for (auto const& hc : host_Cells) {
for (auto const& u : hc.U)
std::cout << " " << u;
std::cout << "\n";
}
}
I have a vector of custom structs (actually much more complicated than shown here) that I want to process on the GPU. In the uncommented BOOST_COMPUTE_CLOSURE the compute::transform passes the structs by value, processes them and then copies them back.
I would like to pass these by reference as shown in the commented out BOOST_COMPUTE_CLOSURE with compute::for_each, but the kernel fails to compile (Build Program Failure) when the program is run and I have not found any documentation mentioning how this should be achieved.
I know I can achieve passing by reference (pointers actually, since it's C99) by using BOOST_COMPUTE_STRINGIZE_SOURCE and passing a pointer to the entire vector of structs, but I'd like to use the compute::... functions as these seem more elegant.
If you define BOOST_COMPUTE_DEBUG_KERNEL_COMPILATION macro and building OpenCL program fails, the program source and the build log will be written to stdout.
You can't pass by reference in OpenCL C, which you are trying to do in the BOOST_COMPUTE_CLOSURE. I understand that you would like to pass a __global pointer to your closure and modify values of the variable in global memory, not of the local copy of that value. I don't think it's supported in Boost.Compute, because in for_each (and other algorithms) Boost.Compute always passes value to your function/closure.
Of course you can always implement a workaround - add unary & operator, or implement custom device iterator. However, in presented example it would just decrease performance, because it would lead to non-coalesced memory reads and writes. If you have very array of complex structures (AoS), try to change it structure of arrays (SoA) or/and break your structure.

How can i get current thread id in function that runs in thread?

How can i get current thread ID in a function that runs on the thread?
I tried like this but it doesn't work.
#include <thread>
#include <iostream>
using namespace std;
#define NUM_TH 4
void printhello(thread t) {
auto th_id = t.get_id();
cout << "Hello world! Thread ID, "<<th_id<< endl;
}
void main() {
thread th[NUM_TH];
for (int i = 0; i < NUM_TH; i++) {
th[i]=thread(printhello,th[i]);
th[i].join();
}
}
i'm getting error "cannot convert argument 1 from void to t"
Instead of passing the thread to the function, you could access the printhello's executing thread by std::this_thread;
Hence, remove the argument and use std::thread::id this_id = std::this_thread::get_id(); instead.
It doesn't "work" for so many reasons. First of all make sure it compiles. Second, a thread is not like a simple class like a string. You cannot copy threads; you can only move threads. What you're doing is trying to initialize an "empty" thread to then copy another thread on top of it. What you can do, if you want an array, is to use pointers instead. To get current thread id, you have to use this_thread::get_id();
#include <thread>
#include <iostream>
#define NUM_TH 4
using namespace std;
void printhello() {
auto th_id = this_thread::get_id();
cout << "Hello world! Thread ID, "<< th_id << endl;
}
int main() {
thread* th[NUM_TH];
for (int i = 0; i < NUM_TH; i++)
{
th[i] = new thread(printhello);
th[i]->join();
}
}

std::atomic_flag to stop multiple threads

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));
}
}