Saturday, November 1, 2008

9 new messages in 5 topics - digest

comp.programming.threads
http://groups.google.com/group/comp.programming.threads?hl=en

comp.programming.threads@googlegroups.com

Today's topics:

* Portable eventcount (try 2) - 1 messages, 1 author
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/326ca631e09e9905?hl=en
* looking for elegant C++ abstraction around pthread_key_t... - 3 messages, 3
authors
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/92098dc36b54f96a?hl=en
* a really simple C++ abstraction around pthread_t... - 3 messages, 2 authors
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/44190e3b9ac81a69?hl=en
* Dmitriy V'jukov gets published interviewed by Intel... - 1 messages, 1
author
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/f6b75cc06c1e166a?hl=en
* Can semaphore operations replace mutex+cond var? - 1 messages, 1 author
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/38a7afe0e9891fd1?hl=en

==============================================================================
TOPIC: Portable eventcount (try 2)
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/326ca631e09e9905?hl=en
==============================================================================

== 1 of 1 ==
Date: Fri, Oct 31 2008 2:31 pm
From: "Dmitriy V'jukov"


On Oct 31, 10:43 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:

> So far so good. Well, it seems like this is going to work out...

Great!

> Although,
> this little test only uses `eventcount::signal_all' procedure; I need to
> test `eventcount::signal_one'...

signal_one() must be tested especially, because it creates subtle
situation when signaled thread already wakeup, but thread descriptor
list is still the root in the eventcount.
Actually signal_one() is the only reason to keep back-link to
eventcount in thread descriptor. If there would be only signal_all()
then back-link to eventcount will not be needed.

Dmitriy V'jukov


==============================================================================
TOPIC: looking for elegant C++ abstraction around pthread_key_t...
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/92098dc36b54f96a?hl=en
==============================================================================

== 1 of 3 ==
Date: Fri, Oct 31 2008 2:34 pm
From: Maxim Yegorushkin


On Oct 31, 6:51 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> "Chris M. Thomasson" <n...@spam.invalid> wrote in messagenews:o%HOk.1694$cx5.507@newsfe01.iad...
>
>
>
> > "Maxim Yegorushkin" <maxim.yegorush...@gmail.com> wrote in message
> >news:9a891bd5-77e1-4d92-9097-4e40438dade1@i18g2000prf.googlegroups.com...
> > On Oct 30, 11:48 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> >> > Here is what I am playing around with now:
>
> >> []
>
> >> Have you looked at
> >>http://www.boost.org/doc/libs/1_36_0/doc/html/thread/thread_local_sto...?
>
> > Yeah. I need to look at the actual source-code and see how they deal with
> > handling the TSD dtor callback.

The source code which deals with pthread specifics of TLS is here
http://boost.cvs.sourceforge.net/viewvc/boost/boost/libs/thread/src/tss.cpp?revision=HEAD&view=markup

However, boost does not map thread_specific_ptr to pthread_key_t 1:1.
Instead, they boost threads library uses only one pthread_key_t and
implements its own clean up handler mechanism.

> > It needs to have C-linkage, and I want to
> > see how they get it to understand what type its dealing with. Do they use
> > a base-class, or other trickery that I am not familiar with.

Although all POSIX APIs require pointers to functions with C linkage,
on practice all C++ functions and static member functions have C
linkage, it is name mangling what is different. I don't know of any
platform/compiler where this is not true (my knowledge is limited
though).

This is what I did with my own thread specific pointer (intended to be
used for global variables mostly):

http://ccull.svn.sourceforge.net/viewvc/ccull/trunk/include/threads/tls_ptr.h?revision=1&view=markup

--
Max

== 2 of 3 ==
Date: Fri, Oct 31 2008 3:05 pm
From: "Chris M. Thomasson"

"Maxim Yegorushkin" <maxim.yegorushkin@gmail.com> wrote in message
news:c96cebad-b090-4f34-9751-a37844f067bc@b38g2000prf.googlegroups.com...
On Oct 31, 6:51 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> > "Chris M. Thomasson" <n...@spam.invalid> wrote in
> > messagenews:o%HOk.1694$cx5.507@newsfe01.iad...
> >
> >
> >
> > > "Maxim Yegorushkin" <maxim.yegorush...@gmail.com> wrote in message
> > >news:9a891bd5-77e1-4d92-9097-4e40438dade1@i18g2000prf.googlegroups.com...
> > > On Oct 30, 11:48 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> > >> > Here is what I am playing around with now:
> >
> > >> []
> >
> > >> Have you looked at
> > >>http://www.boost.org/doc/libs/1_36_0/doc/html/thread/thread_local_sto...?
> >
> > > Yeah. I need to look at the actual source-code and see how they deal
> > > with
> > > handling the TSD dtor callback.

> The source code which deals with pthread specifics of TLS is here
> http://boost.cvs.sourceforge.net/viewvc/boost/boost/libs/thread/src/tss.cpp?revision=HEAD&view=markup

> However, boost does not map thread_specific_ptr to pthread_key_t 1:1.
> Instead, they boost threads library uses only one pthread_key_t and
> implements its own clean up handler mechanism.

Ahhh... Okay. Humm, now I wonder why they did it that way. This kind of
seems odd to me. I know that you have to do that on Windows, but under a
POSIX system; why? I suppose it would be good in the sense of you won't run
out of TSD keys. Interesting.


> > > It needs to have C-linkage, and I want to
> > > see how they get it to understand what type its dealing with. Do they
> > > use
> > > a base-class, or other trickery that I am not familiar with.

> Although all POSIX APIs require pointers to functions with C linkage,
> on practice all C++ functions and static member functions have C
> linkage, it is name mangling what is different. I don't know of any
> platform/compiler where this is not true (my knowledge is limited
> though).

> This is what I did with my own thread specific pointer (intended to be
> used for global variables mostly):

> http://ccull.svn.sourceforge.net/viewvc/ccull/trunk/include/threads/tls_ptr.h?revision=1&view=markup

Humm... Well, I was going for something that would be as portable as
possible. Murphy's Law comes to mind:


The first use of your TSD will of course be on a platform that does not use
C-linkage for static member functions.


Yikes! ;^)

== 3 of 3 ==
Date: Fri, Oct 31 2008 3:16 pm
From: Anthony Williams


"Chris M. Thomasson" <no@spam.invalid> writes:

> "Chris M. Thomasson" <no@spam.invalid> wrote in message
> news:o%HOk.1694$cx5.507@newsfe01.iad...
>>
>> "Maxim Yegorushkin" <maxim.yegorushkin@gmail.com> wrote in message
>> news:9a891bd5-77e1-4d92-9097-4e40438dade1@i18g2000prf.googlegroups.com...
>> On Oct 30, 11:48 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
>>> > Here is what I am playing around with now:
>>
>>> []
>>
>>> Have you looked at
>>> http://www.boost.org/doc/libs/1_36_0/doc/html/thread/thread_local_storage.html
>>> ?
>>
>> Yeah. I need to look at the actual source-code and see how they deal
>> with handling the TSD dtor callback. It needs to have C-linkage, and
>> I want to see how they get it to understand what type its dealing
>> with. Do they use a base-class, or other trickery that I am not
>> familiar with.
>
>
> Well, it seems like they are using an abstract base-class.

Yes, I use an abstract base class.

In boost, the actual TSD value is a pointer to a data structure which
contains *all* the thread-specific data for a given thread (it's
currently a linked list). Each entry has its own cleanup function,
which is called through a pointer to an abstract base class.

The TSD dtor callback is an extern "C" function that takes a pointer
to the data structure and calls the cleanup function for each
thread_specific_ptr value used by the current thread.

> I may be wrong; the Boost source-code is pretty hardcore.

:-)

Anthony
--
Anthony Williams
Author of C++ Concurrency in Action | http://www.manning.com/williams

Custom Software Development | http://www.justsoftwaresolutions.co.uk
Just Software Solutions Ltd, Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK


==============================================================================
TOPIC: a really simple C++ abstraction around pthread_t...
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/44190e3b9ac81a69?hl=en
==============================================================================

== 1 of 3 ==
Date: Fri, Oct 31 2008 2:58 pm
From: "Chris M. Thomasson"


"Chris M. Thomasson" <no@spam.invalid> wrote in message
news:yjKOk.682$kd5.147@newsfe01.iad...
> of course I have created a possible DEADLOCK condition! I totally forgot
> to have the bounded_buffer signal/broadcast after it pops something! Here
> is the FIXED version:
>


ARGHGHGGHGHGHH!


I make two other extreme hardcore RETARDED mistakes! Notice how the
procedure `monitor::broadcast()' fuc%ing calls `pthread_cond_signal()'
instead of `pthread_cond_broadcast()' !!!!!!!!


Also, I misspell Monitor!!!!


DAMNIT!!!

[...]


I am really pissed off now! GRRRR!!! Here is current version that
actually broadcasts!!!:


/* 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_active() = 0;

public:
virtual ~thread_base() = 0;

void active_run() {
pthread_create(&m_tid, NULL, thread_entry, this);
}

void active_join() {
pthread_join(m_tid, NULL);
}
};

thread_base::~thread_base() {}

void* thread_entry(void* state) {
reinterpret_cast<thread_base*>(state)->on_active();
return 0;
}


template<typename T>
struct active : public T {
struct guard {
T& m_object;

guard(T& object) : m_object(object) {
m_object.active_run();
}

~guard() {
m_object.active_join();
}
};

active() : T() {
this->active_run();
}

~active() {
this->active_join();
}

template<typename T_p1>
active(T_p1 p1) : T(p1) {
this->active_run();
}

template<typename T_p1, typename T_p2>
active(T_p1 p1, T_p2 p2) : T(p1, p2) {
this->active_run();
}

// [and on and on for more params...]
};


/* Simple Monitor
______________________________________________________________*/
class monitor {
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;

public:
monitor() {
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}

~monitor() {
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
}

struct lock_guard {
monitor& m_monitor;

lock_guard(monitor& monitor_) : m_monitor(monitor_) {
m_monitor.lock();
}

~lock_guard() {
m_monitor.unlock();
}
};

void lock() {
pthread_mutex_lock(&m_mutex);
}

void unlock() {
pthread_mutex_unlock(&m_mutex);
}

void wait() {
pthread_cond_wait(&m_cond, &m_mutex);
}

void signal() {
pthread_cond_signal(&m_cond);
}

void broadcast() {
pthread_cond_broadcast(&m_cond);
}
};


#define when_x(mp_pred, mp_line) \
monitor::lock_guard guard_##mp_line(*this); \
while (! (mp_pred)) this->wait();

#define when(mp_pred) when_x(mp_pred, __LINE__)


/* Simple Usage Example
______________________________________________________________*/
#include <cstdio>
#include <deque>


#define PRODUCE 100000
#define BOUND 1000
#define YIELD 4


template<typename T>
struct bounded_buffer : private monitor {
unsigned const m_max;
std::deque<T> m_buffer;

public:
bounded_buffer(unsigned const max_) : m_max(max_) {}

void push(T const& obj) {
when (m_buffer.size() < m_max) {
m_buffer.push_back(obj);
broadcast();
}
}

T pop() {
T obj;
when (! m_buffer.empty()) {
obj = m_buffer.front();
m_buffer.pop_front();
broadcast();
}
return obj;
}
};


class producer : public thread_base {
bounded_buffer<unsigned>& m_buffer;

void on_active() {
for (unsigned i = 0; i < PRODUCE; ++i) {
m_buffer.push(i + 1);
std::printf("produced %u\n", i + 1);
if (! (i % YIELD)) { sched_yield(); }
}
}

public:
producer(bounded_buffer<unsigned>* buffer) : m_buffer(*buffer) {}
};


struct consumer : public thread_base {
bounded_buffer<unsigned>& m_buffer;

void on_active() {
unsigned i;
do {
i = m_buffer.pop();
std::printf("consumed %u\n", i);
if (! (i % YIELD)) { sched_yield(); }
} while (i != PRODUCE);
}

public:
consumer(bounded_buffer<unsigned>* buffer) : m_buffer(*buffer) {}
};


int main(void) {
{
bounded_buffer<unsigned> b(BOUND);
active<producer> p[] = { &b, &b, &b, &b, &b, &b };
active<consumer> c[] = { &b, &b, &b, &b, &b, &b };
}

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


SHI%!

;^(.......

== 2 of 3 ==
Date: Fri, Oct 31 2008 3:09 pm
From: Szabolcs Ferenczi


On Oct 31, 10:14 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> What exactly do you have in mind wrt integrating monitor, when keyword and
> active object?

I did not meant integrating all the three but it is an interesting
idea too.

I meant that if we have high level wrappers for easy coding of the
monitor construction, it is possible to put together applications
where there are active objects and passive ones for shared data
communication around. One such an example is the producers and
consumers example.

> How far off the corrected version of my example?

It is promising. Better than I expected, however, the `broadcast();'
should be also included into the RAII (the `when' object).

I did not think of using the preprocessor for the task but rather some
pure C++ construction. That is why I thought that the RAII object
could not only be a simple `lock_guard' but something like a
`when_guard'. Then one does not have to explicitly place the
`broadcast();' and the `while (! (mp_pred)) this->wait();' can be part
of the constructor of the `when_guard'.

On the other hand, the preprocessor allows to keep the more natural
syntax.

Best Regards,
Szabolcs

== 3 of 3 ==
Date: Fri, Oct 31 2008 5:03 pm
From: "Chris M. Thomasson"

"Szabolcs Ferenczi" <szabolcs.ferenczi@gmail.com> wrote in message
news:980d8b20-a9bb-4912-a0fb-3f989dba5bcd@r15g2000prh.googlegroups.com...
On Oct 31, 10:14 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
> > What exactly do you have in mind wrt integrating monitor, when keyword
> > and
> > active object?

> I did not meant integrating all the three but it is an interesting
> idea too.

> I meant that if we have high level wrappers for easy coding of the
> monitor construction, it is possible to put together applications
> where there are active objects and passive ones for shared data
> communication around. One such an example is the producers and
> consumers example.

> > How far off the corrected version of my example?

> It is promising. Better than I expected, however, the `broadcast();'
> should be also included into the RAII (the `when' object).

Okay. Also, there was a little problem in the when macros. I need another
level of indirection in order to properly expand the __LINE__ macro. Here is
new version:
________________________________________________________________
class monitor {
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;

public:
monitor() {
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
}

~monitor() {
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
}

struct lock_guard {
monitor& m_monitor;

lock_guard(monitor& monitor_) : m_monitor(monitor_) {
m_monitor.lock();
}

~lock_guard() {
m_monitor.unlock();
}
};

struct signal_guard {
monitor& m_monitor;
bool const m_broadcast;

signal_guard(monitor& monitor_, bool broadcast = true)
: m_monitor(monitor_), m_broadcast(broadcast) {

}

~signal_guard() {
if (m_broadcast) {
m_monitor.broadcast();
} else {
m_monitor.signal();
}
}
};

void lock() {
pthread_mutex_lock(&m_mutex);
}

void unlock() {
pthread_mutex_unlock(&m_mutex);
}

void wait() {
pthread_cond_wait(&m_cond, &m_mutex);
}

void signal() {
pthread_cond_signal(&m_cond);
}

void broadcast() {
pthread_cond_broadcast(&m_cond);
}
};

#define when_xx(mp_pred, mp_line) \
monitor::lock_guard lock_guard_##mp_line(*this); \
monitor::signal_guard signal_guard_##mp_line(*this); \
while (! (mp_pred)) this->wait();

#define when_x(mp_pred, mp_line) when_xx(mp_pred, mp_line)
#define when(mp_pred) when_x(mp_pred, __LINE__)
________________________________________________________________


Now it properly expands __LINE__ and it also automatically broadcasts.


> I did not think of using the preprocessor for the task but rather some
> pure C++ construction. That is why I thought that the RAII object
> could not only be a simple `lock_guard' but something like a
> `when_guard'. Then one does not have to explicitly place the
> `broadcast();' and the `while (! (mp_pred)) this->wait();' can be part
> of the constructor of the `when_guard'.

> On the other hand, the preprocessor allows to keep the more natural
> syntax.

There is a problem using the preprocessor hack; as-is the following code
will deadlock:


struct object : monitor {
int m_state; // = 0

void foo() {
when (m_state == 1) {
// [...];
}

when (m_state == 2) {
// [...];
}
}
};


this is because the local objects created by the first call to `when' will
still be around during the second call; the soultion is easy:


struct object : monitor {
int m_state; // = 0

void foo() {
{ when (m_state == 1) {
// [...];
}
}


{ when (m_state == 2) {
// [...];
}
}
}
};


but looks a bit awkward. Speaking of awkward, the version using pure C++ and
no pre-processor would be kind of painful to code for. You would basically
need to wrap up all the predicates in separate functions. Lets see here...
It would be something like this:


class when {
monitor& m_monitor;

public:
template<typename P>
when(monitor* monitor_, P pred) : m_monitor(*monitor_) {
m_monitor.lock();
while (! pred()) m_monitor.wait();
}

~when() {
m_monitor.broadcast();
m_monitor.unlock();
}
};


template<typename T>
struct buffer : monitor {
unsigned const m_max;
std::deque<T> m_buffer;

bool pred_push() const {
return m_buffer.size() < m_max;
}

bool pred_pop() const {
return ! m_buffer.empty();
}

public:
buffer(unsigned const max_) : m_max(max_) {}

void push(T const& obj) {
when guard(this, pred_push);
m_buffer.push_back(obj);
}

T pop() {
when guard(this, pred_pop);
T obj = m_buffer.front();
m_buffer.pop_front();
return obj;
}
};


This would work, but it forces you to create a special function
per-predicate. Also, it suffers from the same problem the macro version
does. Two when guard objects residing in the same scope will deadlock...


Humm, personally, I kind of like the macro version better. It seems cleaner
for some reason and allows one to use full expressions for the predicate
instead of a special function. What would be neat is if I use an expression
as a template parameter and have it be treated as if it were a function. The
preprocessor makes this easy...


==============================================================================
TOPIC: Dmitriy V'jukov gets published interviewed by Intel...
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/f6b75cc06c1e166a?hl=en
==============================================================================

== 1 of 1 ==
Date: Fri, Oct 31 2008 2:52 pm
From: Szabolcs Ferenczi


On Oct 31, 10:16 pm, "Dmitriy V'jukov" <dvyu...@gmail.com> wrote:
> On Oct 31, 10:22 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
> wrote:
>
>
>
> > On Oct 31, 7:49 pm, "Chris M. Thomasson" <n...@spam.invalid> wrote:
>
> > > The relevant information is contained within the "Featured Article" section
> > > and its entitled "Q&A with a TBB Junkie":
>
> > >http://www.devx.com/go-parallel
>
> > > very nice
>
> > Congratulations to Dmitriy.
>
> > He writes: "I've developed a library for unit-testing/formal
>
> > verification of synchronization algorithms (or small pieces of multi-
> > threaded code). It's called Relacy Race Detector."
>
> > I am afraid the Relacy Race Detector has nothing to do with unit
> > testing. However, if he really has developed a unit testing library
> > for multi-threading, that would be interesting.
>
> It's exactly for unit-testing. One expresses unit-test and Relacy Race
> Detector executes it efficiently wrt probability of multi-threading
> error detection.

You talked about a library for unit testing that you say now that you
do not have. Well, I am afraid you do not exactly know what unit
testing is.

Nevertheless, you can demonstrate something about it here.

Best Regards,
Szabolcs


==============================================================================
TOPIC: Can semaphore operations replace mutex+cond var?
http://groups.google.com/group/comp.programming.threads/browse_thread/thread/38a7afe0e9891fd1?hl=en
==============================================================================

== 1 of 1 ==
Date: Fri, Oct 31 2008 7:28 pm
From: David Schwartz


On Oct 31, 12:53 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> ... so they can do it one at a time since mutual exclusion is provided
> by the mutex.
>
> Best Regards,
> Szabolcs

My brain took a brief vacation on that one. It's back now. The code I
was "correcting" does substantially the same thing as my corrected
code does.

DS

==============================================================================

You received this message because you are subscribed to the Google Groups "comp.programming.threads"
group.

To post to this group, visit http://groups.google.com/group/comp.programming.threads?hl=en

To unsubscribe from this group, send email to comp.programming.threads+unsubscribe@googlegroups.com

To change the way you get mail from this group, visit:
http://groups.google.com/group/comp.programming.threads/subscribe?hl=en

To report abuse, send email explaining the problem to abuse@googlegroups.com

==============================================================================
Google Groups: http://groups.google.com/?hl=en

No comments: