thread_guard vs scoped_thread - c++

In the book
"C++ Concurrency In Action" by Anthony Williams
you can find the following two snippet of code (I have introduced some slight modifications):
Snippet 1:
class thread_guard
{
std::thread& t;
public:
explicit thread_guard(std::thread& t_): t(t_){}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&)=delete;
thread_guard& operator=(thread_guard const&)=delete;
};
void my_func()
{
for(int j = 0; j < 1000; ++j)
{
cout << "\n " << j;
}
}
void f()
{
std::thread t1(my_func);
thread_guard g(t1);
do_something_in_current_thread();
}
int main()
{
f();
return 0;
}
Going on you can find
Snippet 2:
class scoped_thread
{
std::thread t;
public:
explicit scoped_thread(std::thread t_): t(std::move(t_))
{
if(!t.joinable())
throw std::logic_error(“No thread”);
}
~scoped_thread()
{
t.join();
}
scoped_thread(scoped_thread const&)=delete;
scoped_thread& operator=(scoped_thread const&)=delete;
};
void my_func()
{
for(int j = 0; j < 1000; ++j)
{
cout << "\n " << j;
}
}
void f()
{
scoped_thread st1(thread(my_func));
thread t2(my_func);
scoped_thread st2(move(t2));
do_something_in_current_thread();
}
int main()
{
f();
return 0;
}
I'm not sure that I can really appreciate the real difference between these 2 snippets.
The only difference that I can see is that in Snippet 1 the instance of thread_guard does not take ownership of the thread t1 (unlike a scoped_thread object) and so it could be possible call t1.join() but this is not a problem when ~thread_guard() is executed.
So: where is (if exists) the advantage of Snippet 2?

Both types are meant to block on destruction (e.g. scope exit) until a thread finishes. The difference is in the ownership of the thread object.
thread_guard doesn't own the thread itself; there may be more than one thread_guard waiting on the same thread. This also means that the thread object must be alive as long as any thread_guard refers to it. If the referenced thread has already been joined when a thread_guard object is destroyed, it won't block or produce an error (as opposed to just calling join on a thread that is not joinable).
scoped_thread, on the other hand, takes ownership of the thread instance, and therefore also controls its lifetime. You would use it whenever you want to own the thread you want to wait on, e.g. as a data member.
Ultimately, which one you use is a question of semantics: do you want to wait on a thread someone else owns (then you also have to make sure there are no lifetime issues), or do you want a thread object that blocks when it gets destroyed, without you having to join it first.

In terms of functionality these both implementation are capable to server the purpose, the only difference i can see in these two implementation is, Snippet 2 can accept both lvalue(glvalue) and rvalue(prvalue) but Snippet 1 can't accept rvalue(prvalue) as constructor argument. For example consider following code,
std::thread getThread()
{
return std::thread([](){ std::cout<< __PRETTY_FUNCTION__<< std::endl;});
}
int main( int , char *[])
{
thread_guard g( getThread());
return 0;
}
Now if you compile this code, compile will give following error,
error: cannot bind non-const lvalue reference of type ‘std::thread&’ to an rvalue of type ‘std::remove_reference<std::thread&>::type’ {aka ‘std::thread’}
explicit thread_guard(std::thread _t): t(std::move( _t)){ std::cout<< __PRETTY_FUNCTION__<< std::endl;}
But snippet 2 implementation will work fine.

Related

No matching overloaded function found - Threads

For the code snippet below, I keep getting the invoke error C6272. I have tried multiple things - passing using ref, without it and even testing as a simple thread. For context, the member function is a function that multiplies two sparse matrices and adds them to a linked list. Without using threads, the function works fine but threads returns an error.
mutex m;
vector<thread> a;
for (int q = 0; q < rhs.num_columns_; q++) {
a.push_back(thread(&SparseMatrix::mul_node, rhs_rows, lhs_rows, q, ref(newMatrix), ref(m)));
}
for (thread& t : a) {
t.join();
}
Declaration of the mul_node function
void SparseMatrix::mul_node(vector<vector<int>> rhs, vector<vector<int>> lhs, int pos_rhs, row_node* &newMatrix, mutex &m) const`
I have not been able to find a solution yet for the problem above, please let me know what exactly is causing the issue and how I can fix it? Thank you
Since the member function is not static you need to pass a pointer to the instance of the SparseMatrix on to the std::thread constructor too.
Simplified example:
#include <iostream>
#include <thread>
struct foo {
~foo() {
if(th.joinable()) th.join();
}
void run() {
th = std::thread(&foo::thread_func, this, 10, 20);
// ^^^^
}
void thread_func(int a, int b) {
std::cout << "doing the stuff " << a << ' ' << b << '\n';
}
std::thread th;
};
int main() {
foo f;
f.run();
}
Here 10 and 20 are passed as parameters to this->thread_func.

How to start a variable number of threads in C++?

I am searching for a way to start multiple threads whose exact number can only be determined at runtime. The threads are not dependent on each other, so it's a fire-and-forget kind of problem.
The threads do need some context which is stored as internal variables of a class (Foo). Some of these variables are references. The class also holds a method that should be executed as the thread function (bar).
#include <iostream>
#include <string>
#include <vector>
#include <thread>
class Foo
{
public:
Foo(int a){
std::cout << "Created" << std::endl;
m_a = new int(a);
}
~Foo(){
std::cout << "Destroyed" << std::endl;
delete m_a;
}
void bar() {
std::cout << "Internal var: " << *m_a << std::endl;
}
private:
int* m_a;
};
int main() {
for(int i = 0; i < 5; i++) {
std::thread t(&Foo::bar, std::ref(Foo(i)));
// the threads will be joined at a later point, this is for demo purposes
}
return 0;
}
I get a compile error at this point:
error: use of deleted function ‘void std::ref(const _Tp&&) [with _Tp = Foo]’
I get it that this error is caused because of the temporary nature of the object created in the for-loop. But if I remove the std::ref function, I get a segfault: double free or corruption (fasttop)
I am sure that there must be a way of doing this, but I am unaware of that. I would expect some output like (probably in this order, but not guaranteed):
Created
Internal var: 0
Destroyed
Created
Internal var: 1
Destroyed
...
Thanks!
Problem 1: Foo is missing a copy/move constructor. See The rule of three/five/zero.
Add a copy constructor:
Foo(Foo const& that) : m_a(new int(*that.m_a)) {}
And/or a move constructor:
Foo(Foo && that) : m_a(that.m_a) { that.m_a = nullptr; }
Problem 2: Foo(i) is a temporary instance of Foo, it lives until the end of the full-expression (the ;).
std::thread t(&Foo::bar, std::ref(Foo(i)));
// ^
// Foo(i) is dead at this point while the thread is starting!
You want it to live longer than that, in order to be usable inside the thread.
For example, like this (also answers your question about creating threads in a loop):
int main() {
std::vector<Foo> inputs;
std::vector<std::thread> threads;
for(int i = 0; i < 5; i++) {
inputs.emplace_back(i);
threads.emplace_back(&Foo::bar, &inputs.back());
}
for (auto& t : threads) {
t.join();
}
}
Note: std::ref(Foo(i)) doesn't compile because it has protection against returning references to temporaries (precisely to prevent issues like these).
Here is a minimaly fixed version of your code:
it includes the move ctor for Foo class (and explicitely deletes copy ctor)
it moves the threads into a vector
it joins the threads
Code:
#include <string>
#include <vector>
#include <thread>
#include <iostream>
class Foo
{
public:
Foo(int a) {
std::cout << "Created" << std::endl;
m_a = new int(a);
}
~Foo() {
if (m_a != NULL) {
std::cout << "Destroyed" << std::endl;
delete m_a;
}
}
Foo(const Foo& other) = delete; //not used here
Foo(Foo&& other) {
std::cout << "Move ctor" << '\n';
m_a = other.m_a;
other.m_a = nullptr;
}
void bar() {
std::cout << "Internal var: " << *m_a << std::endl;
}
private:
int* m_a;
};
int main() {
std::vector<std::thread> vec;
for (int i = 0; i < 5; i++) {
std::thread t(&Foo::bar, Foo(i));
vec.push_back(std::move(t));
}
for (auto& t : vec) {
t.join();
}
return 0;
}
The chief design failure seems that t is a variable inside the loop. That means it's destroyed at the end of each iteration - you never have 5 std::thread instances at the same time. Also, you fail to call join on those threads.
The std::ref apparently hides this problem and replaces it with another problem, but your original thread creation was correct: std::thread t(&Foo::bar, Foo(i)).
You probably want a std::list<std::thread>, and use std::list::emplace_back to create a variable amount. std::list<std::thread> allows you to remove threads in any order from the list.

c++ Creating a new thread from a member function and moving the object and the entire

according to the code bellow, is myClass1 object and myClass2 obj (which is the myClass1 object's member ) moving to the new thread with their memory(Like std::move()) ?
class myClass1{
public:
myClass2 obj;
myClass1(myClass2 * obj) {
this.obj = *obj;
}
thread spawn() {
return std::thread([this] { this->Run(); });
}
void Run() {
cout << "new thread" << endl;
}
}
myClass2{
public :
string str;
MyClass2(string str){
this.str = str;
}
}
int main(){
myClass1 object(new myClass2("test"));
thread t = object.spawn();
t.join();
........
}
As it stands, your main will call std::terminate, because you discard a joinable std::thread.
If you join it, main will block until the thread has finished. object will remain alive for the entire duration of Run.
If you detach it, main may end before the thread does, object will cease to exist and the this in myClass1::Run will be invalid. Undefined Behaviour.
A tidy up of your code
class myClass1 {
myClass2 obj;
public:
// Take by rvalue, uses the move constructor for obj
myClass1(myClass2 && obj) : obj(obj) {}
std::thread spawn() {
return std::thread([this]
{
// This is suspicious, but safe
auto self = std::move(*this);
self.Run();
});
}
void Run() {
std::cout << "new thread" << std::endl;
}
}
int main(){
// new is not required
myClass1 object(myClass2("test"));
object.spawn().join();
/* other stuff, not involving object */
return 0;
}
Even more of a tidy up
class myClass1 {
myClass2 obj;
public:
// Take by rvalue, uses the move constructor for obj
myClass1(myClass2 && obj) : obj(obj) {}
void Run() {
std::cout << "new thread" << std::endl;
}
}
int main() {
// Just create the instance of myClass1 as a parameter to `std::thread`'s constructor
std::thread(&myClass1::Run, myClass1(myClass2("test"))).join();
/* other stuff */
return 0;
}
No; creating a thread does not magically make the thread take ownership of that memory. If you create an object on the stack, create a thread that uses it; and then unwind the stack, destroying the object; with the thread still running, you will have undefined behaviour.
If you want to give ownership of some data to the thread, the easiest way to do it is with a shared pointer.

Atomic types and threads

this is the next step after this topic: Modifying data in threads
class Nginx_sender
{
private:
std::atomic_int data;
boost::mutex mMutex;
void SendMessage(const std::string &msg)
{
mMutex.lock();
data++;
mMutex.unlock();
std::cout << "DATA: " << data << std::endl;
}
void NewThreadFunction()
{
while(true) {
mMutex.lock();
std::cout << data;
mMutex.unlock();
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
}
};
int main()
{
Nginx_sender *NginxSenderHandle;
boost::thread sender(boost::bind(&Nginx_sender::NewThreadFunction, &NginxSenderHandle));
// ...
}
In NewThreadFunction the data is always 0 and in SendMessage it changes each time I call SendMessage. So, what's the right way to work with this?
Why are you passing a Nginx_sender ** (double pointer) to boost::bind? That seems wrong, and would explain why your thread appears to be operating on a second copy of the object than the main thread.
Remove the & from the second argument to bind. You already have a pointer to the object, and that's what you're likely trying to use. Secondly, the pointer is uninitialized which could also be a source of you problem. Note, you'll have to be sure the object remains valid until the thread is joined.
int main()
{
Nginx_sender *NginxSenderHandle = new Nginx_sender ;
boost::thread sender(boost::bind(&Nginx_sender::NewThreadFunction, NginxSenderHandle));
// ...
}

std::vector of objects with a boost::thread encapsulated insde

How do I create a std::vector of objects, and each object has a boost::thread encapsulated inside.
class INSTRUMENT {
public:
INSTRUMENT() : m_thread(new boost::thread(&INSTRUMENT::Start, this)) {
x = "abc";
}
~INSTRUMENT() {}
void Start();
public:
std::string x;
boost::shared_ptr<boost::thread> m_thread;
};
void INSTRUMENT::Start() {
try {
while (1) {
boost::this_thread::interruption_point();
std::cout << "here " << x << std::endl;
}
} catch (boost::thread_interrupted &thread_e) {
std::cout << "exit " << x << std::endl;
} catch (std::exception &e) {
}
}
std::vector<INSTRUMENT> m_inst_vector;
for (int i = 0; i < 5; i++) {
m_inst_vector.push_back(INSTRUMENT());
}
The code compiles fine, but the output is just some garbage, not "abc" as expected. In debug, I notice that ~INSTRUMENT() is called every time when .push_back() is called.
I tried not to use boost::group_thread, because of the limitation on the current design. Just wondering whether it is possible to have a std::vector of objects with a thread inside, or any suggestion to a similar design would be very helpful.
I find a similar thread on SO. It mentioned about move-semantics supported in compiler, but didn't explain what it is.
How can I add boost threads to a vector
Thanks.
There are two problems with this code.
Firstly, the thread starts running immediately the boost::thread object is constructed, so you need to ensure that any data it accesses is initialized beforehand --- i.e. initialize x in the member initialization list prior to constructing the thread.
Secondly, the thread uses the this pointer of the INSTRUMENT object, so your object is tied to a specific address. std::vector copies values around: when you call push_back then it copies the object into the vector, and adding additional elements may copy the others around if a new memory block has to be allocated to make room. This is the cause of the destructor calls you see: the temporary is constructed, push_back copies it to the vector, and then the temporary is destructed.
To fix this, you need to ensure that once constructed your INSTRUMENT objects cannot be moved or copied, as copies have the wrong semantics. Do this by making your copy constructor and assignment operator private and unimplemented (or marking them deleted if you have a recent compiler that supports this new C++11 construct), or deriving from boost::noncopyable. Having done this then you no longer need a shared_ptr for the thread, as it cannot be shared, so you can just construct it directly.
If INSTRUMENT is not copyable, you can't store it directly in a vector, so use something like boost::shared_ptr<INSTRUMENT> in the vector. This will allow the vector to freely copy and reshuffle its elements, without affecting the address of the INSTRUMENT object, and ensuring that it is correctly destroyed at the end.
class INSTRUMENT: boost::noncopyable {
public:
INSTRUMENT() : x("abc"),m_thread(&INSTRUMENT::Start, this) {
}
~INSTRUMENT() {}
void Start();
public:
std::string x;
boost::thread m_thread;
};
void INSTRUMENT::Start() {
try {
while (1) {
boost::this_thread::interruption_point();
std::cout << "here " << x << std::endl;
}
} catch (boost::thread_interrupted &thread_e) {
std::cout << "exit " << x << std::endl;
} catch (std::exception &e) {
}
}
std::vector<boost::shared_ptr<INSTRUMENT> > m_inst_vector;
for (int i = 0; i < 5; i++) {
m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT));
}
EDIT: You have a race condition in your code. The thread starts before x gets initialized.
You should change the vector to vector<boost::shared_ptr<INSTRUMENT> >, and remove the boost::shared_ptr from inside INSTRUMENT.
class INSTRUMENT {
public:
INSTRUMENT() {
x = "abc";
m_thread = boost::thread(&INSTRUMENT::Start, this)
}
~INSTRUMENT() {}
void Start();
public:
std::string x;
boost::thread m_thread;
};
for (int i = 0; i < 5; i++) {
m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT()));
}