
Mark Sizer wrote:
I know there was a discussion about the need for these and why they're not in the library. I can't find it, however.
I'm having the same problem the original poster had: I'm using the thread ID as an identifier in a data structure (std::map in this case).
You can do that with Windows thread IDs, because they are simple integers. Unfortunately the Posix thread ID type (pthread_t) is an abstract data type and the only relation defined on it is equality (pthread_equal()). Some implementations use a type that can safely and correctly be compared with std::less, but there's no guarantee of that, so Boost can't offer such a guarantee either.
Now that I'm converting to the Boost threads library, I have to change that. I'm not sure what to do instead.
Any help, either a pointer to the original discussion or direct suggestions, will be much appreciated.
How about using pointers to boost::thread objects as IDs (they must of course be the instances used to start the thread, rather than instances created with the default constructor). Store each thread's own pointer in TLS (or TSS as Boost.Threads calls it). (This is tricky, though - you can't pass a thread's own ID to its initial function, as threads start to run immediately. I suppose you could use placement new, but that's a bit gross.) What's the need for thread IDs, anyway? Are you using a thread pool?

Ben Hutchings said:
Mark Sizer wrote:
I know there was a discussion about the need for these and why they're not in the library. I can't find it, however.
I'm having the same problem the original poster had: I'm using the thread ID as an identifier in a data structure (std::map in this case).
You can do that with Windows thread IDs, because they are simple integers. Unfortunately the Posix thread ID type (pthread_t) is an abstract data type and the only relation defined on it is equality (pthread_equal()). Some implementations use a type that can safely and correctly be compared with std::less, but there's no guarantee of that, so Boost can't offer such a guarantee either.
Actually, we can, and do in the thread_dev branch. It means that the ID is of implementation defined type, but it's portable. -- William E. Kempf

William E. Kempf wrote:
Actually, we can, and do in the thread_dev branch. It means that the ID is of implementation defined type, but it's portable.
In the mean time I would probably do something like the following: (obviously it needs a bit of fleshing out) template<class T> class thread_map { class wrapper; public: typedef const wrapper* id; id create(const boost::function1<void, id> &f, const T& data) { boost::mutex::scoped_lock lock(m); threads.push_back(boost::shared_ptr<wrapper>(new wrapper(f))); return ids.insert(std::make_pair(threads.back().get(), data)).first->first; } T& operator[](id x) { boost::mutex::scoped_lock lock(m); std::map<id, T>::iterator i(ids.find(x)); if (i == ids.end()) throw std::out_of_range("Thread ID does not exist"); return i->second; } private: class wrapper : boost::noncopyable { boost::thread t; public: explicit wrapper(boost::function1<void, id> f) : t(boost::bind<void>(f, this)) {} }; boost::mutex m; std::map<id, T> ids; std::vector<boost::shared_ptr<wrapper> > threads; }; void mythread(thread_map<int>::id id) { /* do something */ } void f() { thread_map<int> threads; thread_map<int>::id id(threads.create(&mythread, 42)); DEBUG_ASSERT(threads[id] == 42); }

Thanks for the idea. I may end up going this route (because it's more like the current code), but I think the thread_specific_ptr<> is the "right" choice. - Mark Sam Partington wrote:
William E. Kempf wrote:
Actually, we can, and do in the thread_dev branch. It means that the ID is of implementation defined type, but it's portable.
In the mean time I would probably do something like the following: (obviously it needs a bit of fleshing out)
template<class T> class thread_map { class wrapper; public: typedef const wrapper* id;
id create(const boost::function1<void, id> &f, const T& data) { boost::mutex::scoped_lock lock(m); threads.push_back(boost::shared_ptr<wrapper>(new wrapper(f))); return ids.insert(std::make_pair(threads.back().get(), data)).first->first; }
T& operator[](id x) { boost::mutex::scoped_lock lock(m); std::map<id, T>::iterator i(ids.find(x)); if (i == ids.end()) throw std::out_of_range("Thread ID does not exist"); return i->second; }
private: class wrapper : boost::noncopyable { boost::thread t; public: explicit wrapper(boost::function1<void, id> f) : t(boost::bind<void>(f, this)) {} }; boost::mutex m; std::map<id, T> ids; std::vector<boost::shared_ptr<wrapper> > threads; };
void mythread(thread_map<int>::id id) { /* do something */ }
void f() { thread_map<int> threads; thread_map<int>::id id(threads.create(&mythread, 42)); DEBUG_ASSERT(threads[id] == 42); }
Info: <http://www.boost.org> Wiki: <http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl> Unsubscribe: <mailto:boost-users-unsubscribe@yahoogroups.com>
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/

Ah, the ever helpful meta-question... The thread ID is being used to pull context information out of a map so that the methods know what set of stuff to operate upon. This sounds like thread_specific_ptr<> to me. Thanks! - Mark Ben Hutchings wrote:
Mark Sizer wrote:
I know there was a discussion about the need for these and why they're not in the library. I can't find it, however.
I'm having the same problem the original poster had: I'm using the thread ID as an identifier in a data structure (std::map in this case).
You can do that with Windows thread IDs, because they are simple integers. Unfortunately the Posix thread ID type (pthread_t) is an abstract data type and the only relation defined on it is equality (pthread_equal()). Some implementations use a type that can safely and correctly be compared with std::less, but there's no guarantee of that, so Boost can't offer such a guarantee either.
Now that I'm converting to the Boost threads library, I have to change that. I'm not sure what to do instead.
Any help, either a pointer to the original discussion or direct suggestions, will be much appreciated.
How about using pointers to boost::thread objects as IDs (they must of course be the instances used to start the thread, rather than instances created with the default constructor). Store each thread's own pointer in TLS (or TSS as Boost.Threads calls it). (This is tricky, though - you can't pass a thread's own ID to its initial function, as threads start to run immediately. I suppose you could use placement new, but that's a bit gross.)
What's the need for thread IDs, anyway? Are you using a thread pool?
Info: <http://www.boost.org> Wiki: <http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl> Unsubscribe: <mailto:boost-users-unsubscribe@yahoogroups.com>
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
participants (4)
-
Ben Hutchings
-
Mark Sizer
-
Sam Partington
-
William E. Kempf