Monday, April 27, 2009

comp.programming.threads - 10 new messages in 6 topics - digest

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

comp.programming.threads@googlegroups.com

Today's topics:

* On the necessity of threads having sleep time... - 1 messages, 1 author
http://groups.google.com/group/comp.programming.threads/t/cef03add05d20ff9?hl=en
* Callback between Threads - 2 messages, 2 authors
http://groups.google.com/group/comp.programming.threads/t/c6d51d417103192d?hl=en
* Joe Seighs awesome rw-spinlock with a twist; the beauty of eventcounts... -
2 messages, 1 author
http://groups.google.com/group/comp.programming.threads/t/be3871ad661efa73?hl=en
* single-producer/consumer bounded queue in Relacy... - 1 messages, 1 author
http://groups.google.com/group/comp.programming.threads/t/d073f161117f8fd0?hl=en
* Library design for canceling a running operation? - 2 messages, 2 authors
http://groups.google.com/group/comp.programming.threads/t/2b4b6c02486bc346?hl=en
* another one of my experimental rw-mutex algorihtms; in Relacy... - 2
messages, 1 author
http://groups.google.com/group/comp.programming.threads/t/3b02a2989a1c25ee?hl=en

==============================================================================
TOPIC: On the necessity of threads having sleep time...
http://groups.google.com/group/comp.programming.threads/t/cef03add05d20ff9?hl=en
==============================================================================

== 1 of 1 ==
Date: Sat, Apr 25 2009 7:26 pm
From: David Schwartz


On Apr 25, 7:17 pm, fguy...@gmail.com wrote:
> food for thought David, and a different perspective. Thanks.

Let me add one more thought, responding to:

"If the purpose of threads is to allow for multitasking and sharing of
resources ..."

The purpose of threads is two-fold:

1) If one thread blocks, for some reason, the application as a whole
is not stalled. Threads allow your application to continue to make
forward progress even if it has to do something that is best done in a
blocking way.

2) If the implementation supports it and chooses to let you do it,
threads allow you to do more than one thing at at time. But they (in
most implementations) do not guarantee that you can do more than one
thing at a time, and the implementation chooses which thread will run
unless you compel it otherwise.

You should know the precise rules for the threading API you are using.
You should assume the worst choices on the part of the implementation.
If they break your application, your application is broken.

In POSIX-land, for example, you are guaranteed that if at least one of
your threads can make forward progress, it will run. However, unless
you specify thread priorities, you are not guaranteed any particular
order or time. (For example, the implementation may choose to always
run the ready-to-run thread has been around the longest. When a lock
is released, it may give it to the oldest thread if it wants to.)

If you have a thread that is always ready-to-run, it is perfectly
sensible for the implementation to always run that thread. If you
care, and you think that's bad, then your designed your program badly,
because it's doing work other than the work you most want done.

It is your responsibility to code your application so that it does the
work you need it it do. It is the implementation's responsibility to
run whichever thread(s) are most efficient.

DS

==============================================================================
TOPIC: Callback between Threads
http://groups.google.com/group/comp.programming.threads/t/c6d51d417103192d?hl=en
==============================================================================

== 1 of 2 ==
Date: Sun, Apr 26 2009 3:10 am
From: davidpryce123@yahoo.com.au


Hi Group,

I am attempting to write a program that has two threads using PThreads
in C++ on Mac OSX.

The main thread is a GUI. The second thread reads from a USB to
serial device with a blocked read.

I have been looking for an C++ OO and thread safe technique for the
USB thread to inform the GUI thread about the receipt of data or a
change in the RS232 signals.

Basically in my main function I start a thread that read from the USB
device. At the moment I an just writing the data read from the USB to
stdout to confirm that the USB code works okay.

From what I have read on the net is the best approach is to use a
callback.

Does anyone have a reference to simple an C++ OO example that might
explain how I can do this?

I am rather new to multi threaded applications and I would like to
understand the best technique to use.

Thanks

David


== 2 of 2 ==
Date: Sun, Apr 26 2009 9:15 pm
From: David Schwartz


On Apr 26, 3:10 am, davidpryce...@yahoo.com.au wrote:

> The main thread is a GUI.  The second thread reads from a USB to
> serial device with a blocked read.
>
> I have been looking for an C++ OO and thread safe technique for the
> USB thread to inform the GUI thread about the receipt of data or a
> change in the RS232 signals.

Why? Why not just have the thread that already knows that data has
been received do whatever needs to be done when data is received?
What's the logic of handing the information off to another thread when
one perfectly good thread already has the information.

> From what I have read on the net is the best approach is to use a
> callback.

I'm not sure what you mean by a callback. If you must hand it off to
another thread, probably the best approach is to queue the object to
the list of events the GUI thread already handles. If the GUI thread
is event driven, just add a 'USB data received' event to its incoming
event queue.

DS

==============================================================================
TOPIC: Joe Seighs awesome rw-spinlock with a twist; the beauty of eventcounts..
.
http://groups.google.com/group/comp.programming.threads/t/be3871ad661efa73?hl=en
==============================================================================

== 1 of 2 ==
Date: Sat, Apr 25 2009 9:58 pm
From: "Chris M. Thomasson"


You can use an eventcount to add conditional blocking behavior to the
spinlock... Here is pseudo-code sketch of the algorithm:
_________________________________________________________________________
class rwmutex {
enum constant {
READ_ACCESS = 0x10000,
WRITE_ACCESS = 1
};


atomic_word m_next; // = 0
atomic_word m_current; // = 0
eventcount m_waitset;


bool prv_check_read(atomic_word ticket) {
return (ticket == (LOAD(&m_current) % READ_ACCESS);
}


bool prv_check_write(atomic_word ticket) {
return (ticket == LOAD(&m_current));
}

public:
void rdlock() {
atomic_word ticket = FETCH_ADD(&m_next, READ_ACCESS) % READ_ACCESS;
while (! prv_check_read(ticket)) {
eventcount::key_type eckey = m_waitset.get();
if (prv_check_read(ticket)) return;
m_waitset.wait(eckey);
}
}


void rdunlock() {
FETCH_ADD(&m_current, READ_ACCESS);
m_waitset.broadcast_relaxed();
}

public:
void wrlock() {
atomic_word ticket = FETCH_ADD(&m_next, WRITE_ACCESS);
while (! prv_check_write(ticket)) {
eventcount::key_type eckey = m_waitset.get();
if (prv_check_write(ticket)) return;
m_waitset.wait(eckey);
}
}


void wrunlock() {
FETCH_ADD(&m_current, WRITE_ACCESS);
m_waitset.broadcast_relaxed();
}
};
_________________________________________________________________________


I am going to code this up in Relacy to verify it. I will keep you posted...


;^)


== 2 of 2 ==
Date: Sun, Apr 26 2009 2:51 pm
From: "Chris M. Thomasson"

"Chris M. Thomasson" <no@spam.invalid> wrote in message
news:RB4Jl.66320$Ji5.22570@newsfe21.iad...
> You can use an eventcount to add conditional blocking behavior to the
> spinlock... Here is pseudo-code sketch of the algorithm:
> _________________________________________________________________________
> [...]
> _________________________________________________________________________
>
>
>
>
> I am going to code this up in Relacy to verify it. I will keep you
> posted...
>

Here is the algorithm in Relacy:

http://relacy.pastebin.com/f788663a2

It works. However, Relacy is showing that if I use relaxed signaling on the
eventcount, it will deadlock. Therefore, I used fenced signaling and
everything in okay.


==============================================================================
TOPIC: single-producer/consumer bounded queue in Relacy...
http://groups.google.com/group/comp.programming.threads/t/d073f161117f8fd0?hl=en
==============================================================================

== 1 of 1 ==
Date: Sat, Apr 25 2009 10:09 pm
From: "Chris M. Thomasson"


Here is the code:

http://relacy.pastebin.com/f6911ad8e

This uses eventcounts to allow for blocking on queue full/empty conditions.


Enjoy!

==============================================================================
TOPIC: Library design for canceling a running operation?
http://groups.google.com/group/comp.programming.threads/t/2b4b6c02486bc346?hl=en
==============================================================================

== 1 of 2 ==
Date: Sun, Apr 26 2009 3:14 pm
From: Jef Driesen


Hi,

I'm writing a library for communication with a number of external
devices. The main part of the public api is very similar to normal file I/O:

device_t *device = NULL;
device_open (&device, ...);
device_read (device, ...);
device_write (device, ...);
device_close (device);

Since most of the I/O operations are relative slow (ranging from a few
seconds to many minutes) they block the main thread. Especially in a GUI
application that is not acceptable and the code should run in its own
thread to keep the rest of the application responsive.

So far no problem, because the code is thread safe as long as the access
to the device handle from multiple threads is properly synchronized (e.g
no global variables, etc). But now I would like to add the capability to
cancel a running operation. What is the best approach for doing this?

The code should be cross-platform with at least support for Windows,
Linux and Mac. A different implementation for each platform is fine too.

I'm not an expert in threading, but I already came up with some ideas:

1. Killing the worker thread.

Simply expecting the application to kill the worker thread is probably
not a good option, because no cleanup can be performed.

2. Providing some sort of device_cancel() function.

This function would set some flag in the device handle to request
cancellation of the running operation. The library code can than check
this flag whenever it can exit cleanly. It's no problem if the exit is
not immediately. Thus something like this:

struct device_t {
volatile int cancelled;
...
}

device_cancel (device_t *device)
{
device->cancelled = 1;
}

device_read (device_t *device, ...)
{
while (!device->cancelled) {
/* do some slow stuff */
}
}

But to make this work, this function must be safe to be called from
different threads, otherwise it is almost useless. From what I
understand, this code should work as long as reading/writing the flag is
atomic. The question is now how can I achieve this? I have read some
literature that reading/writing integers is usually atomic, but not
always guaranteed. And how about the volatile?

http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/

Now I think another potential problem is when this device_cancel()
function is run while the device handle is being closed in the
device_close() function, this will fail. How could I prevent this? I
have been thinking about introducing a new cancellation object, that
could be attached to the device handle, so it becomes possible to
guarantee the lifetime of the cancellation object is longer than the
device handle.

cancel_t *cancel = NULL;
cancel_create (&cancel);

/* Start in separate thread */
device_t *device = NULL;
device_open (&device, ...);
device_set_cancel (device, cancel);
...
device_close (device);
/* End thread */

cancel_destroy (cancel);

Is this a reasonable (and correct) approach?

3. Any other ideas?

Thanks in advance,

Jef


== 2 of 2 ==
Date: Sun, Apr 26 2009 9:13 pm
From: David Schwartz


On Apr 26, 3:14 pm, Jef Driesen <jefdrie...@hotmail.com.invalid>
wrote:

> I'm writing a library for communication with a number of external
> devices. The main part of the public api is very similar to normal file I/O:
>
> device_t *device = NULL;
> device_open (&device, ...);
> device_read (device, ...);
> device_write (device, ...);
> device_close (device);
>
> Since most of the I/O operations are relative slow (ranging from a few
> seconds to many minutes) they block the main thread. Especially in a GUI
> application that is not acceptable and the code should run in its own
> thread to keep the rest of the application responsive.
>
> So far no problem, because the code is thread safe as long as the access
> to the device handle from multiple threads is properly synchronized (e.g
> no global variables, etc). But now I would like to add the capability to
> cancel a running operation. What is the best approach for doing this?

IMO, the best approach is as follows:

1) When you want to start an operation, you create an object that
reflects that operation. You have a reference to that object and the
thread that's performing the operation has a reference.

2) The operation object contains a mutex, condition variable, and any
information needed to assess the state of the operation.

3) The thread performing the operation updates the operation state and
checks for cancellation under the protection of the mutex. When that
thread is done with the operation or has given up on it, it decrements
its reference count (under the protection of the mutex), freeing it if
the count reaches zero.

4) The code requesting the operation is given the handle to the
operation. It may block on it (which results in a call to
pthread_mutex_[timed}wait) or cancel it (which decrements its
reference count, freeing it if it hits zero).

5) On completion, assuming no cancellation, the thread that created it
detects the completion (by seeing the completion in the status/state
variable) under the protection of the mutex and decrements its
reference, resulting in the reference dropping to zero.

DS

==============================================================================
TOPIC: another one of my experimental rw-mutex algorihtms; in Relacy...
http://groups.google.com/group/comp.programming.threads/t/3b02a2989a1c25ee?hl=en
==============================================================================

== 1 of 2 ==
Date: Sun, Apr 26 2009 6:26 pm
From: "Chris M. Thomasson"


This is an experimental algorihtm that I posted a while back, I think
sometime in 2006. I have always wanted to verify its correctness, so I coded
it up in Relacy:


http://relacy.pastebin.com/faf3155c

It works! However, it can indeed starve writers under heavy read contention.
If this happens during the test, Relacy should spit out a livelock error. I
posted a fix to this starvation issue, and plan to test it in Relacy as
well.

RELACY ROCKS!!!!!!!!!!!!!

=^D

== 2 of 2 ==
Date: Sun, Apr 26 2009 6:32 pm
From: "Chris M. Thomasson"

"Chris M. Thomasson" <no@spam.invalid> wrote in message
news:tR7Jl.72043$_R4.29464@newsfe11.iad...
> This is an experimental algorihtm that I posted a while back, I think
> sometime in 2006. I have always wanted to verify its correctness, so I
> coded it up in Relacy:
>
>
> http://relacy.pastebin.com/faf3155c
>
>
>
> It works!

The version above uses a strong compare-and-swap. C++0x does not guarentee
this property. Here is a version that uses weak compare-and-swap:


http://relacy.pastebin.com/f1c697a96


The difference between the two is that weak CAS can fail spuriously while
strong CAS cannot. I guess the C++0x guys did this to cope with CAS
emulations created with LL/SC.


Anyway, the algorihtm still works with weak CAS.


> However, it can indeed starve writers under heavy read contention. If this
> happens during the test, Relacy should spit out a livelock error. I posted
> a fix to this starvation issue, and plan to test it in Relacy as well.
>
>
>
> RELACY ROCKS!!!!!!!!!!!!!
>
>
>
> =^D

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

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: