- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have some cross-platform code that's compiling and running fine with VS2008 but not gcc 4.4.1. Here's the simplest example I can create:
#include
#ifndef __TBB_thread_H
#include "tbb/compat/thread"
#endif
#include "boost/function.hpp"
using namespace tbb;
class Wibble
{
public:
Wibble(int i){inti = i;}
~Wibble(){}
void Wotcha()
{
std::this_thread::sleep_for(tick_count::interval_t(1.5));
std::cout << "\\n WOTCHA, int is " << inti;
}
int inti;
};
int main()
{
Wibble wib2(6);
boost::function func;
func = &Wibble::Wotcha;
std::thread newthread;
newthread = std::thread(func, &wib2);
std::this_thread::yield();
char c;
std::cout << "\\n Hit a key...";
std::cin >> c;
std::cout << "\\n Finished. Bye";
return 1;
}
This compiles and runs fine on Windows with VS2008, but with gcc 4.1.1 on OpenSUSE I get an error on the assignment operator:
proto/threadtest2.cpp:33: error: no match for operator= in newthread = tbb::internal::tbb_thread_v3(boost::function(((const boost::function&)((const boost::function*)(& func)))), (& wib2))
/home/damien/projects/devframework/binaries/inteltbb/OSS/tbb30_018oss-lin/include/tbb/compat/../tbb_thread.h:165: note: candidates are: tbb::internal::tbb_thread_v3& tbb::internal::tbb_thread_v3::operator=(tbb::internal::tbb_thread_v3&)
scons: *** [bld/linux32debug/proto/bld/threadtest2.o] Error 1
Looking into tbb_thread.h I can see that the assignment operator is there. Have I missed a #define somewhere? I have TBB_IMPLEMENT_CPP0X defined so I don't think I'm conflicting with the C++0x in gcc 4.4 (and I don't have the C++0x flag on anyway).
If I change the assignment to:
std::thread newthread;
std::thread thr(func, &wib2);
newthread = thr;
the compiler is happy. I can do that in my production code too, but I thought the first style of assignment was also acceptable.
Damien
#include
#ifndef __TBB_thread_H
#include "tbb/compat/thread"
#endif
#include "boost/function.hpp"
using namespace tbb;
class Wibble
{
public:
Wibble(int i){inti = i;}
~Wibble(){}
void Wotcha()
{
std::this_thread::sleep_for(tick_count::interval_t(1.5));
std::cout << "\\n WOTCHA, int is " << inti;
}
int inti;
};
int main()
{
Wibble wib2(6);
boost::function
func = &Wibble::Wotcha;
std::thread newthread;
newthread = std::thread(func, &wib2);
std::this_thread::yield();
char c;
std::cout << "\\n Hit a key...";
std::cin >> c;
std::cout << "\\n Finished. Bye";
return 1;
}
This compiles and runs fine on Windows with VS2008, but with gcc 4.1.1 on OpenSUSE I get an error on the assignment operator:
proto/threadtest2.cpp:33: error: no match for operator= in newthread = tbb::internal::tbb_thread_v3(boost::function
/home/damien/projects/devframework/binaries/inteltbb/OSS/tbb30_018oss-lin/include/tbb/compat/../tbb_thread.h:165: note: candidates are: tbb::internal::tbb_thread_v3& tbb::internal::tbb_thread_v3::operator=(tbb::internal::tbb_thread_v3&)
scons: *** [bld/linux32debug/proto/bld/threadtest2.o] Error 1
Looking into tbb_thread.h I can see that the assignment operator is there. Have I missed a #define somewhere? I have TBB_IMPLEMENT_CPP0X defined so I don't think I'm conflicting with the C++0x in gcc 4.4 (and I don't have the C++0x flag on anyway).
If I change the assignment to:
std::thread newthread;
std::thread thr(func, &wib2);
newthread = thr;
the compiler is happy. I can do that in my production code too, but I thought the first style of assignment was also acceptable.
Damien
1 Solution
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My practical advice is simply don't copy thread objects. Use pointers or smart pointers if you really need to move about a reference to a thread.
But from the purely academic standpoint your case is rather curious. So let's talk a little bit about it.
If you take a closer look at the assignment operator declaration, you'll see that it accepts non-const reference to its source argument (right-hand side operand). In expression
newthread = std::thread(func, &wib2);
the source operand is rvalue, which makes the assignment invalid. MS compiler applies non-standard extension here, but issues a warning.
The reason for such a design is that std::thread is just an avatar of a kernel mode object, and copying it cannot create a copy of the actual thread. Therefore the assignmnt operation is destructive for the source operand. Its intestines are torn out and placed into the assignee, which now becomes the sole owner of the underlying kernel object.
But your observation is curious from another standpoint. Originally TBB provided class tbb_thread because there was not such class in the standard library. But when C++0x draft had matured enough, we've decided to masquerade TBB specific class as the upcoming standard std::thread one to simplify adoption of the new C++ Standard by our users.
However here a hitch awaited us. C++0x defines assignment operator in the following way:
thread& operator=(thread&& x);
It uses rvalue reference! Exactly for the same purpose I mentioned above - to pass ownership of the underlying OS entity to the new instance of the wrapper class. And the problem is that if at some moment in the future you try to compile your working variant with the real standard library, it won't compile! Because in the expression
newthread = thr;
source operand is lvalue, and lvalue cannot be bound to the rvalue reference.
To make if future proof, you could use move() helper:
tbb::move( newthread, thr );
But note that this move() is TBB specific.
But from the purely academic standpoint your case is rather curious. So let's talk a little bit about it.
If you take a closer look at the assignment operator declaration, you'll see that it accepts non-const reference to its source argument (right-hand side operand). In expression
newthread = std::thread(func, &wib2);
the source operand is rvalue, which makes the assignment invalid. MS compiler applies non-standard extension here, but issues a warning.
The reason for such a design is that std::thread is just an avatar of a kernel mode object, and copying it cannot create a copy of the actual thread. Therefore the assignmnt operation is destructive for the source operand. Its intestines are torn out and placed into the assignee, which now becomes the sole owner of the underlying kernel object.
But your observation is curious from another standpoint. Originally TBB provided class tbb_thread because there was not such class in the standard library. But when C++0x draft had matured enough, we've decided to masquerade TBB specific class as the upcoming standard std::thread one to simplify adoption of the new C++ Standard by our users.
However here a hitch awaited us. C++0x defines assignment operator in the following way:
thread& operator=(thread&& x);
It uses rvalue reference! Exactly for the same purpose I mentioned above - to pass ownership of the underlying OS entity to the new instance of the wrapper class. And the problem is that if at some moment in the future you try to compile your working variant with the real standard library, it won't compile! Because in the expression
newthread = thr;
source operand is lvalue, and lvalue cannot be bound to the rvalue reference.
To make if future proof, you could use move() helper:
tbb::move( newthread, thr );
But note that this move() is TBB specific.
Link Copied
2 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My practical advice is simply don't copy thread objects. Use pointers or smart pointers if you really need to move about a reference to a thread.
But from the purely academic standpoint your case is rather curious. So let's talk a little bit about it.
If you take a closer look at the assignment operator declaration, you'll see that it accepts non-const reference to its source argument (right-hand side operand). In expression
newthread = std::thread(func, &wib2);
the source operand is rvalue, which makes the assignment invalid. MS compiler applies non-standard extension here, but issues a warning.
The reason for such a design is that std::thread is just an avatar of a kernel mode object, and copying it cannot create a copy of the actual thread. Therefore the assignmnt operation is destructive for the source operand. Its intestines are torn out and placed into the assignee, which now becomes the sole owner of the underlying kernel object.
But your observation is curious from another standpoint. Originally TBB provided class tbb_thread because there was not such class in the standard library. But when C++0x draft had matured enough, we've decided to masquerade TBB specific class as the upcoming standard std::thread one to simplify adoption of the new C++ Standard by our users.
However here a hitch awaited us. C++0x defines assignment operator in the following way:
thread& operator=(thread&& x);
It uses rvalue reference! Exactly for the same purpose I mentioned above - to pass ownership of the underlying OS entity to the new instance of the wrapper class. And the problem is that if at some moment in the future you try to compile your working variant with the real standard library, it won't compile! Because in the expression
newthread = thr;
source operand is lvalue, and lvalue cannot be bound to the rvalue reference.
To make if future proof, you could use move() helper:
tbb::move( newthread, thr );
But note that this move() is TBB specific.
But from the purely academic standpoint your case is rather curious. So let's talk a little bit about it.
If you take a closer look at the assignment operator declaration, you'll see that it accepts non-const reference to its source argument (right-hand side operand). In expression
newthread = std::thread(func, &wib2);
the source operand is rvalue, which makes the assignment invalid. MS compiler applies non-standard extension here, but issues a warning.
The reason for such a design is that std::thread is just an avatar of a kernel mode object, and copying it cannot create a copy of the actual thread. Therefore the assignmnt operation is destructive for the source operand. Its intestines are torn out and placed into the assignee, which now becomes the sole owner of the underlying kernel object.
But your observation is curious from another standpoint. Originally TBB provided class tbb_thread because there was not such class in the standard library. But when C++0x draft had matured enough, we've decided to masquerade TBB specific class as the upcoming standard std::thread one to simplify adoption of the new C++ Standard by our users.
However here a hitch awaited us. C++0x defines assignment operator in the following way:
thread& operator=(thread&& x);
It uses rvalue reference! Exactly for the same purpose I mentioned above - to pass ownership of the underlying OS entity to the new instance of the wrapper class. And the problem is that if at some moment in the future you try to compile your working variant with the real standard library, it won't compile! Because in the expression
newthread = thr;
source operand is lvalue, and lvalue cannot be bound to the rvalue reference.
To make if future proof, you could use move() helper:
tbb::move( newthread, thr );
But note that this move() is TBB specific.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Andrey,
This is a really good description of thread move semantics with assignment. It makes a lot more sense now. I'll change my design to use pointers instead of assignment; the design is for long-running, fire-and-forget tasks. Extra news and deletes won't make any difference and I'd rather not use move.
Damien
This is a really good description of thread move semantics with assignment. It makes a lot more sense now. I'll change my design to use pointers instead of assignment; the design is for long-running, fire-and-forget tasks. Extra news and deletes won't make any difference and I'd rather not use move.
Damien

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page