Hi. I believe that there is a bug in thread::thread() under Windows. The code uses GetCurrentThread() WinAPI function, but this is not enough. If you'll try to create such a thread object, and pass its reference to another thread which will join it - something like struct SomeThread { thread *m_thread; SomeThread(thread *a_thread) : m_thread(a_thread) { } void operator()() { do_some_work() m_thread->join(); delete m_thread; } }; { ...somewhere in the code... SomeThread st(new thread()); thread other_thread(st); } then it won't work. The following is a quote from MSDN about GetCurrentThread(): "The return value is a pseudo handle for the current thread... A pseudo handle is a special constant that is interpreted as the current thread handle... The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function." The conclusion is that a call to DuplicateHandle() is needed after GetCurrentThread(). Thanks, Yuval
On Wed, 8 Dec 2004 11:44:18 +0200, Yuval Ronen
Hi. I believe that there is a bug in thread::thread() under Windows. The code uses GetCurrentThread() WinAPI function, but this is not enough. If you'll try to create such a thread object, and pass its reference to another thread which will join it - something like [...]
A default-constructed thread is documented as being non-joinable: http://boost.org/doc/html/thread.html#id401409-bb -- Caleb Epstein caleb dot epstein at gmail dot com
Hi. I believe that there is a bug in thread::thread() under Windows. The code uses GetCurrentThread() WinAPI function, but this is not enough. If you'll try to create such a thread object, and pass its reference to another thread which will join it - something like [...]
A default-constructed thread is documented as being non-joinable:
Ok, I can't join it. So what can I do with it?
On Wed, 8 Dec 2004 20:27:10 +0200, Yuval Ronen
A default-constructed thread is documented as being non-joinable:
Ok, I can't join it. So what can I do with it?
Not a whole heck of a lot aside from comparing it to other threads. -- Caleb Epstein caleb dot epstein at gmail dot com
A default-constructed thread is documented as being non-joinable: Ok, I can't join it. So what can I do with it? Not a whole heck of a lot aside from comparing it to other threads.
This brings me some thoughts. The thread class is non-copyable (which is fine by me) and also it has an operator==. I think these two things contradict each other. When defining an equal operator, we are actually defining semantics for copying: copying an object will result in a second object that will be equal, in terms of operator==, to the first object. Defining an equal operator means that objects can be equal, or in other works, they are a copies of the same value! To strengthen my point, I'll say that this not just theory, it's also partially been done in practice, here in the thread class. The no-parameters constructor is just that - it copies the current thread. The result of the no-parameters constructor is a copy of the object representing the current thread. Copies can be done! IMHO, there are two possibilities: The first is to declare that threads are in fact copyable and providing full support for that (copy constructor, etc.). And again, copying them means creating a second object that is 'opeator==' equal to the first. The second possibility is to insist that threads are non-copyable. That means that the no-parameters constructor and the equal opeator have to go, because they contradict this concept. But do we loose functionality if we erase those? If we agree that the only use for them is the ablity to write some like like: bool is_current_thread(const thread &t) { return t == thread(); } then it would be much better to have a member function bool thread::is_current() const; that will do just that. It's much more accurate and expressive to use ' if (some_thread.is_current())' then to use 'if (some_thread == thread())'. I hope I was persuasive, Yuval
Yuval Ronen wrote:
A default-constructed thread is documented as being non-joinable:
Ok, I can't join it. So what can I do with it?
Not a whole heck of a lot aside from comparing it to other threads.
This brings me some thoughts. The thread class is non-copyable (which is fine by me) and also it has an operator==. I think these two things contradict each other. When defining an equal operator, we are actually defining semantics for copying: copying an object will result in a second object that will be equal, in terms of operator==, to the first object. Defining an equal operator means that objects can be equal, or in other works, they are a copies of the same value! <snip>
As I see it, the problem is that thread combines the functions of thread ID and thread handle. Joinable and non-joinable thread objects are two very different types and the type system should reflect that. I think that thread should be separated into two classes: class thread_id // Exposition only { public: // construct/copy/destruct thread_id(); thread_id(const thread_id &); ~thread_id(); // modifier thread_id & operator=(const thread_id &); // comparison bool operator==(const thread_id &) const; bool operator!=(const thread_id &) const; }; class thread : private boost::noncopyable // Exposition only { public: // construct/copy/destruct explicit thread(const boost::function0<void>&); ~thread(); // modifier void join(); // static static void sleep(const xtime&); static void yield(); }; Then every thread object would be joinable and every thread_id would be copiable. Ben.
As I see it, the problem is that thread combines the functions of thread ID and thread handle.
This is not a problem. I was talking purly about the thread interface, and this is implementation. Also I can add that this implementation is not limiting the interface in any way (remember the DuplicateHandle() from the first message), so no problem.
Joinable and non-joinable thread objects are two very different types and the type system should reflect that. I think that thread should be separated into two classes:
class thread_id // Exposition only { public: // construct/copy/destruct thread_id(); thread_id(const thread_id &); ~thread_id();
// modifier thread_id & operator=(const thread_id &);
// comparison bool operator==(const thread_id &) const; bool operator!=(const thread_id &) const; };
class thread : private boost::noncopyable // Exposition only { public: // construct/copy/destruct explicit thread(const boost::function0<void>&); ~thread();
// modifier void join();
// static static void sleep(const xtime&); static void yield(); };
Then every thread object would be joinable and every thread_id would be copiable.
Ben.
According to your proposition, if I understood correctly, there is no no-parameters constructor to thread, and all threads are joinable. This is exactly what I was preaching to in my suggestion, so there is no argument between us there. The difference is that you offer to add a new thread_id class which I think is of no use at all. You need to add some kind of connection between class thread and class thread_id, something like: thread_id thread::get_thread_id(); // thread method and then you'll go around and compare thread_ids. What for? If we agree that threads cannot be copied, it means that each thread can be represented by only one thread object. Pass the address of thread objects and compare them, if you really want to. It'll give you the exact same result. Yuval
Yuval Ronen wrote: [...]
According to your proposition, if I understood correctly, there is no no-parameters constructor to thread, and all threads are joinable. This is exactly what I was preaching to in my suggestion, so there is no argument between us there. The difference is that you offer to add a new thread_id class which I think is of no use at all. You need to add some kind of connection between class thread and class thread_id, something like: thread_id thread::get_thread_id(); // thread method and then you'll go around and compare thread_ids. What for?
For thread_id get_current_thread_id(); presumably.
If we agree that threads cannot be copied,
We don't. More details below.
it means that each thread can be represented by only one thread object. Pass the address of thread objects and compare them, if you really want to. It'll give you the exact same result.
The problem with your reasoning is that the thread object may have been
destroyed. Its lifetime is not tied to the lifetime of the thread.
Threads are noncopyable for historical reasons. Bill Kempf's original design
had copyable, reference counted threads. Beman Dawes argued that a thread is
conceptually very similar to an fstream, so it should be noncopyable, and
Bill found his arguments convincing enough. I argued for what seemed like an
eternity that this is wrong, and the user should never see a thread
"object", only a thread handle (tentatively called thread_ref at the time) -
essentially a shared_ptr
I believe that we are going a bit off the topic here, but I'll go there with
you.
What you are suggesting, is that what we now know as 'thread' will be
transformed into 'thread_impl' and will be hidden from the user, which will
only know about thread_ref (actually a shared_ptr
Yuval Ronen wrote:
[...]
According to your proposition, if I understood correctly, there is no no-parameters constructor to thread, and all threads are joinable. This is exactly what I was preaching to in my suggestion, so there is no argument between us there. The difference is that you offer to add a new thread_id class which I think is of no use at all. You need to add some kind of connection between class thread and class thread_id, something like: thread_id thread::get_thread_id(); // thread method and then you'll go around and compare thread_ids. What for?
For
thread_id get_current_thread_id();
presumably.
If we agree that threads cannot be copied,
We don't. More details below.
it means that each thread can be represented by only one thread object. Pass the address of thread objects and compare them, if you really want to. It'll give you the exact same result.
The problem with your reasoning is that the thread object may have been destroyed. Its lifetime is not tied to the lifetime of the thread.
Threads are noncopyable for historical reasons. Bill Kempf's original design had copyable, reference counted threads. Beman Dawes argued that a thread is conceptually very similar to an fstream, so it should be noncopyable, and Bill found his arguments convincing enough. I argued for what seemed like an eternity that this is wrong, and the user should never see a thread "object", only a thread handle (tentatively called thread_ref at the time) - essentially a shared_ptr
. The proposed API was thread_ref create_thread( F f ); thread_ref current_thread(); void join( thread_ref tr );
I was unable to convince Bill Kempf to change the design (back), however.
Yuval Ronen wrote:
I believe that we are going a bit off the topic here, but I'll go there with you.
What you are suggesting, is that what we now know as 'thread' will be transformed into 'thread_impl' and will be hidden from the user, which will only know about thread_ref (actually a shared_ptr
). First of all, in no way do I dismiss this proposal. But what is the difference between this and the current design?
The difference is: Current design: (thread data, including function object) (thread class, noncopyable) thread_ref design: (thread data) The current design has two logical object per thread, one that remains alive until the thread finishes execution, another that is created by the user and can be destroyed at any time.
Another thing: if we want a thread_ref current_thread(); function, how will it be implmented?
A thread_ref is held in thread-specific storage (keeping the thread object alive for the lifetime of the thread as a side effect) and is returned by current_thread().
Hello boost::thread experts, does the 'thread_ref-design' as discussed previously enable the following scenario ? <code start> struct thread_class_1 { thread_ref tr; void operator()() { tr = get_current_thread_ref(); // view from *inside* a thread ... } } ; ... thread_class_1 thread_functor_1; boost::thread thread_1(thread_functor_1) ; ... // assume the thread really started in the meantime ... thread_ref tr_1 = thread_functor_1.tr; // view from *outside* a thread // assume the thread is still working ... thread_ref tr_2 = thread_1.get_thread_ref(); // view from *outside* a thread ... <code end> Now tr_1 == tr_2 evaluates to true. To my understanding the current implementation of boost::thread does not allow easy comparison of threads from *inside* and *outside*. Grouping the boost::thread members m_thread,m_id,.. into a comparable type (e.g. named thead_id) and exposing this id at least 'protected' would make user extensions more flexible. Thanks for any reply, Martin. Peter Dimov wrote:
Yuval Ronen wrote:
I believe that we are going a bit off the topic here, but I'll go there with you.
What you are suggesting, is that what we now know as 'thread' will be transformed into 'thread_impl' and will be hidden from the user, which will only know about thread_ref (actually a shared_ptr
). First of all, in no way do I dismiss this proposal. But what is the difference between this and the current design? The difference is:
Current design:
(thread data, including function object) (thread class, noncopyable)
thread_ref design:
(thread data)
The current design has two logical object per thread, one that remains alive until the thread finishes execution, another that is created by the user and can be destroyed at any time.
Another thing: if we want a thread_ref current_thread(); function, how will it be implmented?
A thread_ref is held in thread-specific storage (keeping the thread object alive for the lifetime of the thread as a side effect) and is returned by current_thread().
Martin Pasdzierny wrote:
Hello boost::thread experts,
does the 'thread_ref-design' as discussed previously enable the following scenario ? <code start>
struct thread_class_1 { thread_ref tr; void operator()() { tr = get_current_thread_ref(); // view from *inside* a thread ... } } ; ... thread_class_1 thread_functor_1; boost::thread thread_1(thread_functor_1) ;
There are two problems with this code. First, under the thread_ref design, there is no boost::thread class: thread_ref thread1 = create_thread( thread_functor_1 ); Second, create_thread makes a copy of thread_functor_1 and runs the copy, as is also the case with the current design. However, thread1, as returned by create_thread, and the thread_ref returned by current_thread inside the newly spawned thread will indeed be equivalent. They will not only compare equal, but will be interchangeable in every way.
Peter Dimov wrote:
Martin Pasdzierny wrote:
Hello boost::thread experts,
does the 'thread_ref-design' as discussed previously enable the following scenario ? <code start>
struct thread_class_1 { thread_ref tr; void operator()() { tr = get_current_thread_ref(); // view from *inside* a thread ... } } ; ... thread_class_1 thread_functor_1; boost::thread thread_1(thread_functor_1) ;
There are two problems with this code. First, under the thread_ref design, there is no boost::thread class:
thread_ref thread1 = create_thread( thread_functor_1 );
Second, create_thread makes a copy of thread_functor_1 and runs the copy, as is also the case with the current design. OK. (In real world I usually do some smart_ptr wrapping around the functors data members)
However, thread1, as returned by create_thread, and the thread_ref returned by current_thread inside the newly spawned thread will indeed be equivalent. They will not only compare equal, but will be interchangeable in every way. Very good.
Do You plan to change the current implementation ( would be a partial re-implementation) ? As I posted in another thread: My personal impression is that an alternative change to the current implementation would enable at least this extended comparability: - exposing the (currently internal) thread identifiers (such as thread::m_id thread::m_thread etc.) as a comparable type thread::id at least as 'protected'. - thread_group (optionally) gets an additional member like: thread* get_thread(thread:id id);
However, thread1, as returned by create_thread, and the thread_ref returned by current_thread inside the newly spawned thread will indeed be equivalent. They will not only compare equal, but will be interchangeable in every way. Very good.
Do You plan to change the current implementation ( would be a partial re-implementation) ?
How about comparing address of thread objects (using the current design)? Will that satisfy your needs? As I explained some messages ago, if threads are noncopyable, you can use address of thread objects as a comparable thread_id, while not needing the implementation details (such the Windows handles) at all. If you use this, you need to be careful not to create a thread using the no-parameters constructor, becuase it will entirely ruin my philosophy...
Yuval Ronen wrote:
However, thread1, as returned by create_thread, and the thread_ref returned by current_thread inside the newly spawned thread will indeed be equivalent. They will not only compare equal, but will be interchangeable in every way.
Very good.
Do You plan to change the current implementation ( would be a partial
re-implementation) ?
How about comparing address of thread objects (using the current design)? Will that satisfy your needs?
It would, as long as I have the threads address available from *inside* the thread. But to my understanding boost::thread::thread() does *not* return a globally addressable object. At the end of this posting You will find a compilable but dangerously simplyfied example to demontrate my needs. Its main idea is to make the global boost::thread objects address available through a thread_specific_pointer object. The used approach is far from *elegant* but I didn't find something better. (Having the threads id available from *inside* a static-like call to boost::thread::thread().id() as well as from *outside* by the threads objects method 'id' would simplify the example ...)
As I explained some messages ago, if threads are noncopyable, you can use address of thread objects as a comparable thread_id, while not needing the implementation details (such the Windows handles) at all. If you use this, you need to be careful not to create a thread using the no-parameters constructor, becuase it will entirely ruin my philosophy... ???
// g++ -pthread -W -Wall -lboost_thread-gcc-mt thread_pointer_test.cpp -o thread_pointer_test #include <iostream> #include <set> #include "boost/thread.hpp" #include "boost/thread/tss.hpp" #include "boost/thread/xtime.hpp" boost::thread_specific_ptrboost::thread* current_thread_; std::setboost::thread* some_global_thread_pointers ; void wait(int sec) { boost::xtime wait_until; boost::xtime_get(&wait_until, boost::TIME_UTC); wait_until.sec += sec; boost::thread::sleep(wait_until); } void some_global_func() { if(current_thread_.get()) { std::cout << "\nsome_global_func uses current_thread_:" << *current_thread_ << std::flush; // in real life some_global_thread_pointers must be protected with mutexes std::setboost::thread*::iterator it = some_global_thread_pointers.find(*current_thread_); if(it != some_global_thread_pointers.end()) std::cout << "\nsome_global_func found myself in some_global_thread_pointers" << std::flush; else std::cout << "\nsome_global_func did not find myself in some_global_thread_pointers" << std::flush; } } struct thread_functor { boost::thread** this_pointer_; thread_functor(boost::thread** address_of_this) : this_pointer_(address_of_this) { } void operator()() { wait(1); std::cout << "\nthis_pointer_:" << this_pointer_; std::cout << "\n*this_pointer_:" << *this_pointer_; if(this_pointer_ && *this_pointer_) { std::cout << "\ninitializing current_thread_ ..." << std::flush; current_thread_.reset(this_pointer_); } else std::cout << "\nfailed to initialize current_thread_" << std::flush; wait(1); // call other functions etc. some_global_func(); std::cout << "\nmy_thread ends" << std::flush; current_thread_.release(); // I'm not really happy with the 'assymetric' need to call this method ;-( } }; int main(int argc, char** argv) { boost::thread *my_thread_1(0),*my_thread_2(0); thread_functor my_functor_1(&my_thread_1),my_functor_2(&my_thread_2); my_thread_1 = new boost::thread(my_functor_1); std::cout << "\n&my_thread_1:" << &my_thread_1 << std::flush; std::cout << "\nmy_thread_1:" << my_thread_1 << std::flush; my_thread_2 = new boost::thread(my_functor_2); std::cout << "\n&my_thread_2:" << &my_thread_2 << std::flush; std::cout << "\nmy_thread_2:" << my_thread_2 << std::flush; wait(2); some_global_thread_pointers.insert(my_thread_1); std::cout << "\ninserted my_thread_1 into some_global_thread_pointers, waiting for my_threads to join" << std::flush; my_thread_1->join(); my_thread_2->join(); delete my_thread_1; delete my_thread_2; std::cout << "\n...bye\n" << std::flush; }
How about comparing address of thread objects (using the current design)? Will that satisfy your needs?
It would, as long as I have the threads address available from *inside* the thread. But to my understanding boost::thread::thread() does *not* return a globally addressable object.
Yes, you're right. You can't really get a boost::thread form inside the thread. To this end I suggetsed the bool thread::is_current() const; member function which doesn't return a thread object, but assumes the all you need to do with the current thread object is compare it to other threads, so it offers a replacement. But until this is added (or the thread library is completely refactored using other design such as the thread_ref design), this is a problem.
What you are suggesting, is that what we now know as 'thread' will be transformed into 'thread_impl' and will be hidden from the user, which will only know about thread_ref (actually a shared_ptr
). First of all, in no way do I dismiss this proposal. But what is the difference between this and the current design? The difference is:
Current design:
(thread data, including function object) (thread class, noncopyable)
thread_ref design:
(thread data)
and: thread_ref class (which might just be a shared_ptr
The current design has two logical object per thread, one that remains alive until the thread finishes execution, another that is created by the user and can be destroyed at any time.
The same in the thread_ref design. The thread_impl is kept alive, while the thread_ref is created and deleted at the user's will.
Another thing: if we want a thread_ref current_thread(); function, how will it be implmented?
A thread_ref is held in thread-specific storage (keeping the thread object alive for the lifetime of the thread as a side effect) and is returned by current_thread().
That pops another question: what to do with the main thread? What will happen if the user will call current_thread() while in the main thread? You somehow have to create a thread_impl of the main thread before the start of main() function, and store it in the tss. Perhaps using global/static objects that the compiler will care for initilizing before main()? Very dangerous (especially with Windows DLLs). Of course you can ask me the same question: what to do in such case using the noncopyable design? Well, I was hoping you didn't ask... :-) First, if you can find a solution to this problem with your design, then maybe I can use the same technique and store a thread object representing the main thread, and also supply a thread& get_main_thread() function. Alternatively, I can say that there is no main thread object. Is this a bad solution? What would I loose? I'd loose the opportunity to do 'main_thread.join()', but that just might be a good thing. I'd also loose the possibility to comapre the address of the main thread object to addresses of other threads. Hmmm... Well, I hope that's not a problem... Definitely something to think about.
Peter Dimov wrote:
Yuval Ronen wrote:
[...]
If we agree that threads cannot be copied,
We don't. More details below.
Sorry for jumping in between. But I always was wondering what "copying a thread" could mean. Innocently I would expect creating a second instance of the thread similar to a "fork" of processes in unix. But I don't think this is what you have in mind. Otherwise copying the whole state of a thread is not of much sense either (thread needs to be scheduled.) I think noncopyable is a property of a thread, and the design simply refelcts this fact, but I might be wrong in this respect and would like to hear what I am missing.
it means that each thread can be represented by only one thread object. Pass the address of thread objects and compare them, if you really want to. It'll give you the exact same result.
The problem with your reasoning is that the thread object may have been destroyed. Its lifetime is not tied to the lifetime of the thread.
This is true. But where is the problem? Once I have deleted the thread
object (not the thread!) I am not
able to compare it to anything, since the memory is invalid, isn't it?
As I see it, the demand for thread ID's or references mainly come from
the attempt to
communicate with the thread. (Are there really other usages?) So not
having a thread ID
is no drawback at all, since this problem can be solved easily by other
means.
I append a small example showing how a thread can communicate with another,
using a control object with automatic lifetime:
Some remarks
1) from inside the thread I use a tls that holds the communication object
2) from outside I use a wrapper object
3) control of lifetime of this object is tricky, since it must last as
long as both
communicating threads have agreed to dipose it.
#include
Roland Schwarz wrote:
Peter Dimov wrote:
Yuval Ronen wrote:
[...]
If we agree that threads cannot be copied,
We don't. More details below.
Sorry for jumping in between. But I always was wondering what "copying a thread" could mean. [...]
It doesn't mean anything. A thread cannot be copied. boost::thread is not a thread, however.
The problem with your reasoning is that the thread object may have been destroyed. Its lifetime is not tied to the lifetime of the thread. This is true. But where is the problem? Once I have deleted the thread object (not the thread!) I am not able to compare it to anything, since the memory is invalid, isn't it?
Well, of course. The problem is that this is an unnecessary limitation. Since the thread still exists, it should be possible to identify it; and a requirement that the user should make sure that the boost::thread outlives its corresponding thread is so 1996.
As I see it, the demand for thread ID's or references mainly come from the attempt to communicate with the thread.
The demand for thread ID's come from the need to _identify_ the thread. In POSIX terms, every operation that takes a pthread_t uses it to identify the thread on which it is supposed to operate. Currently the only identifier provided by the library is boost::thread, and the only allowed operation on a thread is join.
Peter Dimov wrote:
The demand for thread ID's come from the need to _identify_ the thread. In POSIX terms, every operation that takes a pthread_t uses it to identify the thread on which it is supposed to operate.
A quick grep over my header file revealed: the first 5 usages are covered by boost thread pthread_create (pthread_t * tid, ... The ctor pthread_detach (pthread_t tid); The dtor pthread_t pthread_self (void); The default ctor pthread_join (pthread_t thread, ... The join function pthread_equal (pthread_t t1, pthread_t t2); The operator()== The remaining are (not yet) supported by boost thread pthread_cancel (pthread_t thread); pthread_setschedparam (pthread_t thread, ... pthread_getschedparam (pthread_t thread, ... pthread_kill(pthread_t thread, int sig); Do I miss some important usages of pthread_t ? To me it appears that the pthread_t type is simply a C language idiom (kind of a handle). It appears to me as not beeing any different than boost::thread* . Please explain to me where I am wrong in my assumptions. What I think is of more importance is to have a common access point to the thread that can be accessed from inside the thread like a TLS variable, while still be accessible from the outside by a mechansim using something like a thread id as an index. Of course to this end the thread must be indentifyable. But this is not sufficient as I tried to point out. (And also I know of no current implementation of this.) Can you point me please to some other usages of the thread ID beyond the ones above? Roland
Roland Schwarz wrote:
Peter Dimov wrote:
The demand for thread ID's come from the need to _identify_ the thread. In POSIX terms, every operation that takes a pthread_t uses it to identify the thread on which it is supposed to operate.
A quick grep over my header file revealed:
the first 5 usages are covered by boost thread pthread_create (pthread_t * tid, ... The ctor pthread_detach (pthread_t tid); The dtor pthread_t pthread_self (void); The default ctor pthread_join (pthread_t thread, ... The join function pthread_equal (pthread_t t1, pthread_t t2); The operator()==
The remaining are (not yet) supported by boost thread pthread_cancel (pthread_t thread); pthread_setschedparam (pthread_t thread, ... pthread_getschedparam (pthread_t thread, ... pthread_kill(pthread_t thread, int sig);
Do I miss some important usages of pthread_t ? To me it appears that the pthread_t type is simply a C language idiom (kind of a handle). It appears to me as not beeing any different than boost::thread* . Please explain to me where I am wrong in my assumptions.
pthread_self gives you a full pthread_t, which you can use as input to pthread_join, pthread_cancel, pthread_setschedparam; you can also give this pthread_t to another thread and it remains valid. boost::thread::thread() doesn't give you a boost::thread*, the boost::thread surrogate it creates is valid only within the current thread, and it can only be compared to another boost::thread. pthread_self "always works"; it does not depend on some user not destroying a boost::thread object. A boost::thread* in thread-specific storage does not have this property.
Peter Dimov wrote:
pthread_self gives you a full pthread_t, which you can use as input to pthread_join, pthread_cancel, pthread_setschedparam; you can also give this pthread_t to another thread and it remains valid.
boost::thread::thread() doesn't give you a boost::thread*, the boost::thread surrogate it creates is valid only within the current thread, and it can only be compared to another boost::thread.
pthread_self "always works"; it does not depend on some user not destroying a boost::thread object. A boost::thread* in thread-specific storage does not have this property.
Ah, I see. Thank you. Now I understand why W.E.Kempf has given up on the bool m_joinable; attribute in his newer work on thread. He introduced a thread_data structure that lives in tls storage and serves the purposes of pthread_self. The default constructor now essentially is: thread::thread() : m_handle(0) { thread_data* tdata = thread_data::get_current(); tdata->addref(); m_handle = tdata; } And this does give back something that can be used as long as the thread is alive. Roland
Roland Schwarz wrote:
Peter Dimov wrote:
pthread_self gives you a full pthread_t, which you can use as input to pthread_join, pthread_cancel, pthread_setschedparam; you can also give this pthread_t to another thread and it remains valid.
boost::thread::thread() doesn't give you a boost::thread*, the boost::thread surrogate it creates is valid only within the current thread, and it can only be compared to another boost::thread.
pthread_self "always works"; it does not depend on some user not destroying a boost::thread object. A boost::thread* in thread-specific storage does not have this property.
Ah, I see. Thank you. Now I understand why W.E.Kempf has given up on the bool m_joinable; attribute in his newer work on thread. He introduced a thread_data structure that lives in tls storage and serves the purposes of pthread_self. The default constructor now essentially is: thread::thread() : m_handle(0) { thread_data* tdata = thread_data::get_current(); tdata->addref(); m_handle = tdata; } And this does give back something that can be used as long as the thread is alive.
Exactly, the newer boost::thread is essentially a thread_ref. Unfortunately Bill abandoned Boost.Threads shortly after. ;-)
Peter Dimov wrote:
pthread_self gives you a full pthread_t, which you can use as input to pthread_join, pthread_cancel, pthread_setschedparam; you can also give this pthread_t to another thread and it remains valid.
Is this even true after having detached a thread? Is it still valid to join a thread by means of a thread id that has been obtained with pthread_self after the thread has been detached?
boost::thread::thread() doesn't give you a boost::thread*, the boost::thread surrogate it creates is valid only within the current thread, and it can only be compared to another boost::thread.
As long as the boost::thread has not been "delete"ed (the equivalent of detach) you are free to use the boost::thread* from any other thread you like.
pthread_self "always works"; it does not depend on some user not destroying a boost::thread object. A boost::thread* in thread-specific storage does not have this property.
This is indeed an interesting question I would like to know the answer. Again: does "alqays" imply "even after having been detached"? I suspect, that boost::thread* behaves almost identical to pthread_t in a semantical sense. Roland
Roland Schwarz wrote:
Peter Dimov wrote:
pthread_self gives you a full pthread_t, which you can use as input to pthread_join, pthread_cancel, pthread_setschedparam; you can also give this pthread_t to another thread and it remains valid.
Is this even true after having detached a thread? Is it still valid to join a thread by means of a thread id that has been obtained with pthread_self after the thread has been detached?
man pthread_detach says: pthread_detach put the thread th in the detached state. This guarantees that the memory resources consumed by th will be freed immediately when th terminates. However, this prevents other threads from synchronizing on the termination of th using pthread_join.
boost::thread::thread() doesn't give you a boost::thread*, the boost::thread surrogate it creates is valid only within the current thread, and it can only be compared to another boost::thread.
As long as the boost::thread has not been "delete"ed (the equivalent of detach) you are free to use the boost::thread* from any other thread you like.
pthread_self "always works"; it does not depend on some user not destroying a boost::thread object. A boost::thread* in thread-specific storage does not have this property.
This is indeed an interesting question I would like to know the answer. Again: does "alqays" imply "even after having been detached"?
I suspect, that boost::thread* behaves almost identical to pthread_t in a semantical sense.
Do You mean
boost::thread::thread() == *th
with th pointing to a boost::thread is *always* a semantically meaningful expression including the case th pointing to the current thread (but th != &boost::thread::thread()) ?
Martin.
--
Martin Pasdzierny,
Martin Pasdzierny wrote:
Do You mean
boost::thread::thread() == *th
No. I mean comparing the pointers. Of course I know, that there is no boost equivalent of pthread_self available out of the box. However you can easily work around this even without modifying boost::thread if you need it. During startup of the thread you would manage to store a copy of the pointer within a tss variable. If you want to know how this works I can post you an example. This pointer, say "this_thread" can then be used exactly like pthread_self can be used (with equivalent sematics).
with th pointing to a boost::thread is *always* a semantically meaningful expression including the case th pointing to the current thread (but th != &boost::thread::thread()) ?
Of course your last statement is also true. But since boost::thread is not copyable (which is a good thing) it cannot be used easily to identify a thread. Roland
participants (6)
-
Ben Hutchings
-
Caleb Epstein
-
Martin Pasdzierny
-
Peter Dimov
-
Roland Schwarz
-
Yuval Ronen