Re: Question on C++ Thread Class and inheritance/polymorphism with
POSIX pthread
On Oct 29, 12:07 am, "Chris M. Thomasson" <n...@spam.invalid> wrote:
FWIW, here is a quick example (in the form of a fully compliable program
with error checking omitted) of how I use POSIX threads within a C++
environment:
_________________________________________________________________
/* Simple Thread Object
______________________________________________________________*/
#include <pthread.h>
extern "C" void* thread_entry(void*);
class thread_base {
pthread_t m_tid;
friend void* thread_entry(void*);
virtual void on_thread_entry() = 0;
public:
virtual ~thread_base() = 0;
void thread_run() {
pthread_create(&m_tid, NULL, thread_entry, this);
}
void thread_join() {
pthread_join(m_tid, NULL);
}
};
thread_base::~thread_base() {}
void* thread_entry(void* state) {
reinterpret_cast<thread_base*>(state)->on_thread_entry();
return 0;
}
template<typename T>
struct thread : public T {
thread() : T() {
this->thread_run();
}
~thread() {
this->thread_join();
}
template<typename T_p1>
thread(T_p1 p1) : T(p1) {
this->thread_run();
}
template<typename T_p1, typename T_p2>
thread(T_p1 p1, T_p2 p2) : T(p1, p2) {
this->thread_run();
}
// [and on and on for for params...]
};
/* Simple Usage Example
______________________________________________________________*/
#include <string>
#include <cstdio>
class worker : public thread_base {
std::string const m_name;
void on_thread_entry() {
std::printf("(%p)->worker(%s)::on_thread_entry()\n",
(void*)this, m_name.c_str());
}
public:
worker(std::string const& name)
: m_name(name) {
std::printf("(%p)->worker(%s)::my_thread()\n",
(void*)this, m_name.c_str());
}
~worker() {
std::printf("(%p)->worker(%s)::~my_thread()\n",
(void*)this, m_name.c_str());
}
};
int main(void) {
{
thread<worker> workers[] = {
"Chris",
"John",
"Jane",
"Steve",
"Richard",
"Lisa"
};
worker another_worker("Jeff");
another_worker.thread_run();
another_worker.thread_join();
}
std::puts("\n\n\n__________________\nhit <ENTER> to exit...");
std::fflush(stdout);
std::getchar();
return 0;}
_________________________________________________________________
IMVHO, this is very straight forward and works well. In fact, I think I l=
ike
it better than the Boost method... Humm... Well, what do you all think ab=
out
the design? Is it crap?
The active object concept is much better than the Boost thread and I
have suggested it earlier that the C++0x committee should consider
this pattern, i.e. active object, as a high level wrapper construction
next to their high level wrapper wait/2 on the condition variable:
<quote from="
http://groups.google.com/group/comp.lang.c++/msg/8e80468d988c4feb
">
I do think it has advantages over Boost's method. One such advantage
is the RAII nature of it.
Furthermore, I think it should be taken in into the C++0x standard on
the similar grounds as they provide higher level condition variable
wait API as well:
<quote>
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
Effects:
As if:
while (!pred())
wait(lock);
</quote>
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html
</quote>
Another remark: Why do you not keep to the terminology we have come up
with earlier? It is for an active object and not for any plain thread.
See:
"What's the connection between objects and threads?"
http://groups.google.com/group/comp.lang.c++/msg/84d6d69cae17fee7
What is the difference between:
worker another_worker("XY");
another_worker.thread_run();
another_worker.thread_join();
and
ActiveObject<worker> another_worker("XY");
Well, the difference is that the wrapper takes care of the low level
details of starting and stopping the thread. As a bonus, it is
impossible to miss to join the thread. In other frameworks they tend
to call it the fork-join style.
So, you might consider this patch for clarity:
34,35c34,35
< struct ActiveObject : public T {
< ActiveObject() : T() {
---
struct thread : public T {
thread() : T() {
39c39
< ~ActiveObject() {
---
~thread() {
44c44
< ActiveObject(T_p1 p1) : T(p1) {
---
thread(T_p1 p1) : T(p1) {
49c49
< ActiveObject(T_p1 p1, T_p2 p2) : T(p1, p2) {
---
thread(T_p1 p1, T_p2 p2) : T(p1, p2) {
86c86
< ActiveObject<worker> workers[] = {
---
thread<worker> workers[] = {
I believe that the program will be clearer and more readable if you
keep to the terminology that reflects the active object. It is not a
good idea to overload the term `thread' since it will just cause some
more confusion.
Best Regards,
Szabolcs