passing multiple arguments to a threaded function from another class - c++

Say I have a class:
class This
{
void that(int a, int b);
};
and in my main function I need to start 'that' in a thread, and pass it 2 arguments.
This is what I have:
void main()
{
This t;
t.that(1,2); //works unthreaded.
std::thread test(t.that(1,2)); // Does not compile. 'evaluates to a function taking 0 arguments'
std::thread test2(&This::that, std::ref(t), 1, 2); //runs, but crashes with a Debug error.
}
I have searched, but have only found how to pass arguments to a thread, and to run a function from another class in a thread, but not both!
What is the correct way to do this?

In order to run This in another thread you either have to make a copy or ensure that it is still valid as long as the other thread is running. Try one of these:
Reference
This t;
std::thread test([&]() {
t.that(1,2); // this is the t from the calling function
});
// this is important as t will be destroyed soon
test.join();
Copy
This t;
std::thread test([=]() {
t.that(1,2); // t is a copy of the calling function's t
});
// still important, but does not have to be in this function any more
test.join();
Dynamic allocation
auto t = std::make_shared<This>();
std::thread(test[=]() {
t->that(1,2); // t is shared with the calling function
});
// You still have to join eventually, but does not have to be in this function
test.join();

The object t is destroyed at the end of the main() function, but the thread runs for some time after that. It results in an undefined behavior. It is also generally a good idea to join to all threads before quitting the program. Just put this at the end:
test2.join();

This::that does not take a reference to a This as its first argument.
I think what you want to do is more like
auto t = std::make_shared<This>();
std::thread test2{ [t](int a, int b) { t->that(a, b); }, 1, 2 };

Related

c++ Thread handling in class

I would like to create a object in which I can start a thread and have a function to join withe the created thread. Everything insight the object, so that the thread is a private component of the object.
I have tried a bit and got those Results. Could some of you explain me what I have done wrong, and why I get this errors?
A.h
#include <thread>
class A{
std::thread a;
public:
//this should be a void function
std::thread startThread();
void join();
void (*threadFunction)() = nullptr;
};
and the A.cpp
#include "../header/A.h"
std::thread A::startThread()
{
std::thread a((*threadFunction));
return a;
}
void A::join()
{
a.join();
}
main.cpp
void newFunc(){
std::cout<<"I'm a thread"<<std::endl;
}
int main(){
auto object = new A();
object->threadFunction = &newFunc;
//Version 1) Error "terminate called without an active exception"
object->startThread();
object->join();
/*
Version 2) terminate called after throwing an instance of 'std::system_error'
I'm a thread
what(): Invalid argument
*/
auto value = object->startThread();
object->join();
//Version 3) I'm a thread
auto value = object->startThread();
value.join();
}
I don't see the difference. I have stored the thread in the object, so it is not lost... and when I store the return value and don't use it, its almost fine... but not really ... and directly join() is perfect ... I don't get it :D
Please help me
std::thread A::startThread()
{
std::thread a((*threadFunction));
return a;
}
Does not interact with the member variable a, but it creates a new local variable std::thread object and then moves it to the result (unless the move is optimized out). The thread A::a always remains the default constructed one. A default constructed thread object is non-joinable, i.e. throws an exception on the call of std::thread::join. The only thread join can be called for without causing an exception is the thread object returned from the function.
If you don't join the returned thread and its destructor runs (happens when you drop the temporary thread object returned (Version 1)), std::terminate shuts your program down.
To make this work you need to move assign a newly created thread to the member variable and not return the thread object or just return a reference to it:
void A::startThread()
{
a = std::thread(threadFunction);
}
or
std::thread& A::startThread()
{
a = std::thread(threadFunction);
return a;
}
I wouldn't recommend the second alternative, it drastically reduces your ability to enforce class invariants with regards to the thread lifecycle.

Different behaviour while passing shared_ptr to weak_ptr in thread functions and normal functions

I'm having a thread function which takes a weak_ptr<> and I pass my shared_ptr<> in the thread function.
Legally weak_ptr<> should not increment the reference count of shared_ptr<>, however, unless I typecast with weak_ptr<> while passing the same to the thread function, it increments the reference count (unexpected)
This behaviour happens only with thread functions and not with normal function calls.
Here is the code for thread function
void thrdfn(weak_ptr<int> wp) {
cout<<wp.use_count()<<endl; // Prints 2
}
int main() {
shared_ptr<int> sp = make_shared<int>();
thread th { thrdfn, (sp)};
th.join();
return 0;
}
However, when I typecast while creating thread, it behaves properly
void thrdfn(weak_ptr<int> wp) {
cout<<wp.use_count()<<endl; // Prints 1
}
int main() {
thread th { thrdfn, weak_ptr<int>(sp)}; // typecast
}
When I call the function as a normal function call, it works fine without typecasting
void thrdfn(weak_ptr<int> wp) {
cout<<wp.use_count()<<endl; // Prints 1
}
int main() {
shared_ptr<int> sp = make_shared<int>();
thrdfn(sp);
return 0;
}
Behaviour is same with multiple compilers
When you write construct a std::thread (and I removed the superfluous parentheses):
thread th{thrdfn, sp};
What happens is:
The new thread of execution starts executing
std::invoke(decay_copy(std::forward<Function>(f)), decay_copy(std::forward<Args>(args))...);
where decay_copy is defined as
template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }
Which is to say, your shared_ptr is copied into the thread and you take a weak_ptr off of that copy. So there are two shared_ptrs: yours and the thread's.
Avoid trying auto conversion from shared_ptr to weak_ptr, it may create extra shared_ptr. Below snippet should work fine :
shared_ptr<int> sp = make_shared<int>();
weak_ptr<int> weak = sp;
thread th { thrdfn, (weak)};

C++ Stack around variable is corrupted

I am trying to implement a timer, which takes a function pointer as a parameter and a time in milliseconds. After the time is passed, the function should be called in a separate thread. The code looks as follows:
class timer
{
public:
void schedule(void(*function)(), int time)
{
std::thread t = std::thread([&]
{
std::this_thread::sleep_for(std::chrono::milliseconds(time));
function();
});
t.detach();
}
};
The main method looks as follows:
#define LOG(x) std::cout << x << std::endl;
timer t1;
timer t2;
timer t3;
t1.schedule([] {LOG("t1 done")}, 2000);
t2.schedule([] {LOG("t2 done")}, 3000);
t3.schedule([] {LOG("t3 done")}, 4000);
std::this_thread::sleep_for(std::chrono::seconds(20));
The exception is as follows:
Run-Time Check Failure #2 - Stack around the variable 't1' was corrupted.
The issue here is you are capturing by reference in your lambda. This means that it is possible for you to call detach and exit from schedule before the operator() of the lambda is called. If that happens then when you try to use time you are accessing a dangling reference.
The solution here is to capture by value instead. This means you get a copy and it doesn't matter when the operator() is called as the lambda doesn't rely on anything.

Using a vector of thread in another thread : error attempting to reference a deleted function

I'm trying to send a vector to parameter of another thread's function :
void foo(){}
const int n = 24;
void Thread_Joiner(std::vector<thread>& t,int threadNumber)
{
//some code
}
int main()
{
std::vector<thread> threads(n, thread(foo));
thread Control_thread1(Thread_Joiner, threads, 0);//error
thread Control_thread2(Thread_Joiner, threads, 1);//error
//...
}
The above code give this error :
: attempting to reference a deleted function
I checked the header file of std::thread It seems that copy constructor is deleted : thread(const thread&) = delete;
std::thread have a move constructor but I don't think in this case using move is helpfull because Control_thread1 and Control_thread2 use same vector !
If I use thread **threads;... instead of that vector It works fine but I don't want to use pointers .
What should I do ?!
std::thread copies the arguments used for the bind. Use std::ref to contain it as a reference:
std::thread Control_thread1(Thread_Joiner, std::ref(threads), 0);
std::thread Control_thread2(Thread_Joiner, std::ref(threads), 1);

Error about std::promise in C++

I am trying to pass my class instance into threads and the return the processed objects from threads. I've googled about C++ multithreading, and found that std::promising can be helpful.
However, I am stuck at the very beginning. Here is my code:
void callerFunc()
{
//...
std::promise<DataWareHouse> data_chunks;
// DataWareHouse is my customized class
//data_chunks has a vector<vector<double>> member variable
std::thread(&run_thread,data_chunks);
// ............
}
void run_thread(std::promise<DataWareHouse> data_chunks)
{
// ...
vector<vector<double>> results;
// ...
data_chunks.set_value(results);
}
The above code generates an error:
`error C2248: 'std::promise<_Ty>::promise' : cannot access private member declared in class 'std::promise<_Ty>'`
May I know what am I wrong and how to fix it?
Many thanks. :-)
Your first problem is that you are using std::thread -- std::thread is a low level class which you should build higher abstractions up on. Threading is newly standardized in C++ in C++11, and all of the rough parts are not filed off yet.
There are three different patterns for using threading in C++11 that might be useful to you.
First, std::async. Second, std::thread mixed with std::packaged_task. And third, dealing with std::thread and std::promise in the raw.
I'll illustrate the third, which is the lowest level and most dangerous, because that is what you asked for. I would advise looking at the first two options.
#include <future>
#include <vector>
#include <iostream>
typedef std::vector<double> DataWareHouse;
void run_thread(std::promise<DataWareHouse> data_chunks)
{
DataWareHouse results;
results.push_back( 3.14159 );
data_chunks.set_value(results);
}
std::future<DataWareHouse> do_async_work()
{
std::promise<DataWareHouse> data_chunks;
std::future<DataWareHouse> retval = data_chunks.get_future();
// DataWareHouse is my customized class
//data_chunks has a vector<vector<double>> member variable
std::thread t = std::thread(&run_thread,std::move(data_chunks));
t.detach(); // do this or seg fault
return retval;
}
int main() {
std::future<DataWareHouse> result = do_async_work();
DataWareHouse vec = result.get(); // block and get the data
for (double d: vec) {
std::cout << d << "\n";
}
}
Live example
With std::async, you'd have a function returning DataWareHouse, and it would return a std::future<DataWareHouse> directly.
With std::packaged_task<>, it would take your run_thread and turn it into a packaged_task that can be executed, and a std::future extracted from it.
std::promise<> is not copyable, and in calling run_thread() you are implicitly trying to invoke the copy constructor. The error message is telling you that you cannot use the copy constructor since it is marked private.
You need to pass a promise by reference (std::promise<DataWareHouse> &). This is safe if callerFunc() is guaranteed not to return until run_thread() is finished with the object (otherwise you will be using a reference to a destroyed stack-allocated object, and I don't have to explain why that's bad).
You're trying to pass the promise to the thread by value; but you need to pass by reference to get the results back to the caller's promise. std::promise is uncopyable, to prevent this mistake.
std::thread(&run_thread,std::ref(data_chunks));
^^^^^^^^
void run_thread(std::promise<DataWareHouse> & data_chunks)
^
The error is telling you you cannot copy an std::promise, which you do here:
void run_thread(std::promise<DataWareHouse> data_chunks)
and here:
std::thread(&run_thread,data_chunks); // makes copy of data_chunks
You should pass a reference:
void run_thread(std::promise<DataWareHouse>& data_chunks);
// ^
And then pass an std::reference_wrapper to the thread, otherwise it too will attempt to copy the promise. This is easily done with std::ref:
std::thread(&run_thread, std::ref(data_chunks));
// ^^^^^^^^
Obviously data_chunks must be alive until the thread finished running, so you will have to join the thread in callerFunc().