By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,709 Members | 2,211 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,709 IT Pros & Developers. It's quick & easy.

Re: Question on C++ Thread Class and inheritance/polymorphism with POSIX pthread

P: n/a
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<workerworkers[] = {
"Chris",
"John",
"Jane",
"Steve",
"Richard",
"Lisa"
};

worker another_worker("Jeff");
another_worker.thread_run();
another_worker.thread_join();
}

std::puts("\n\n\n__________________\nhit <ENTERto exit...");
std::fflush(stdout);
std::getchar();
return 0;
}
__________________________________________________ _______________


IMVHO, this is very straight forward and works well. In fact, I think I like
it better than the Boost method... Humm... Well, what do you all think about
the design? Is it crap?

Oct 28 '08 #1
Share this Question
Share on Google+
1 Reply


P: n/a
On Oct 29, 12:07*am, "Chris M. Thomasson" <n...@spam.invalidwrote:
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<workerworkers[] = {
* * * "Chris",
* * * "John",
* * * "Jane",
* * * "Steve",
* * * "Richard",
* * * "Lisa"
* * };

* * worker another_worker("Jeff");
* * another_worker.thread_run();
* * another_worker.thread_join();
* }

* std::puts("\n\n\n__________________\nhit <ENTERto exit...");
* std::fflush(stdout);
* std::getchar();
* return 0;}

__________________________________________________ _______________

IMVHO, this is very straight forward and works well. In fact, I think I like
it better than the Boost method... Humm... Well, what do you all think about
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....80468d988c4feb
">
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/wg...008/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....d6d69cae17fee7

What is the difference between:

worker another_worker("XY");
another_worker.thread_run();
another_worker.thread_join();

and

ActiveObject<workeranother_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<workerworkers[] = {
---
thread<workerworkers[] = {
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
Oct 29 '08 #2

This discussion thread is closed

Replies have been disabled for this discussion.