Re: gtkmm-list Digest, Vol 14, Issue 43

2005-07-03 Thread Chris Vine
On Friday 01 July 2005 11:38, Mario Sergio Fujikawa Ferreira wrote:

[snip]

  That does not protect against race conditions. If the
 send_notification (emit()) thread is interrupted right in the middle of
 the write(2) call, we will end up with another thread doing a write(2)
 and another one overlapping is atomicity is not guaranteed. As per the
 POSIX standard upholding, I am not seeing such atomicity guarantees
 under Conectiva Linux 9 kernel 2.4.x series with Linuxthreads. It could
 be just a problem with my development environment (which should not be
 since I am able to reproduce this problem under Mandriva Linux) but we
 should not rely on that but do take a safer approach right from the
 start.

Pipes are, through their file descriptors, a resource shared between processes 
as well as threads.  You can be pretty sure that glibc is providing the 
atomicity guarantees required by POSIX with respect to this, as it tries hard 
to get these things right.

You can therefore take it that there is no race condition in relation to 
different processes writing to the same pipe.  As I said, you are technically 
right in the sense that POSIX only guarantees the position where different 
processes write to the same pipe, not where different threads within any one 
process write to the same pipe.  Even if glibc were not to offer atomicity 
between threads (although it would have to work hard at not providing 
atomicity between threads if it is providing it between processes), I am 
pretty certain that this is not your problem (see further below).  (It is 
difficult to see how interleaved data could cause a lock-up - note that 
write() itself is guaranteed to be thread safe.)

[snip]
  Okay, here is my theory from what I gathered from gdb. This is
 just a theory. Others more experienced with {glib,gtk}mm inner workings
 should know better. Well, under some irregular circunstances it is
 possible to lock up all threads (including the main thread and the
 controller thread for that matter) if a send_notification thread is
 preempted in the middle of it's execution while holding the lock. If
 the main/controller thread tries to use the send_notification (emit()),
 it will end up waiting on that mutex. Dead lock. Any way, even if this
 is not the case, I am experienced deadlocks with that approach.

I think I can see where you are going wrong.  You should not have the same 
thread both (a) calling emit() on the Glib::Dispatcher object (sending the 
notification) and (b) being the thread within which the Glib::MainContext 
polling the pipe for reading executes (and therefore in which the slot 
connected to the Dispatcher executes).  You should normally only emit from a 
worker thread - ie a thread which is not the main thread (Glib::MainContext) 
within which Glib/GTK+ is executing.  Otherwise you can get a deadlock.

This deadlock does not arise as you suggest because of a recursive call to any 
mutex you use (if all you are doing is putting a mutex around the write call 
to the pipe then the same thread which is doing that write cannot at the same 
time also be trying to reacquire the mutex), but because the write is a 
blocking write and when any one thread is writing to the pipe, it cannot also 
be reading from it.

You say you are using the Dispatchers heavily.  If you are stuffing so much 
data into the pipe that it is full before it has a chance to be read by the 
next iteration through the main program loop (Glib::MainContext), then if the 
thread sending the notification is also the one which reads from it then it 
will block on the write for ever because the pipe can never be emptied.

If you are emitting a signal in the same thread as the one in which you want 
the slot connected to it to execute (the main program thread), just use a 
plain sigc::signal0void object in those cases (reserve the Glib::Dispatcher 
for a case where a different thread is sending the notification).  You can 
have a sigc::signal0void object and a Glib::Dispatcher object connected to 
the same slot, and because the slot will (if you adopt this approach) be 
executing in only the main program thread, you will need no mutexes for it.

Chris.
___
gtkmm-list mailing list
gtkmm-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtkmm-list


Re: gtkmm-list Digest, Vol 14, Issue 43

2005-07-01 Thread Mario Sergio Fujikawa Ferreira

The POSIX Single Unix Specification provides in relation to write()
that:

Write requests to a pipe or FIFO shall be handled in the same way as
a
regular file with the following exceptions:

  ...

  Write requests of {PIPE_BUF} bytes or less shall not be interleaved
with
  data from other processes doing writes on the same pipe. Writes of
greater
  than {PIPE_BUF} bytes may have data interleaved, on arbitrary
boundaries,
  with writes by other processes, whether or not the O_NONBLOCK flag
of the
  file status flags is set.

  ...

PIPE_BUF is never less than 512 and is usually 2048 in size.
Admittedly the
standard only requires writes by different processes to be atomic with
a
write of a size not greater than that, but it would be odd if the same
behaviour were not exhibited by different threads within one process.
If you
are using Windows, I thought that it was POSIX compliant?


	That does not protect against race conditions. If the  
send_notification (emit()) thread is interrupted right in the middle of  
the write(2) call, we will end up with another thread doing a write(2)  
and another one overlapping is atomicity is not guaranteed. As per the  
POSIX standard upholding, I am not seeing such atomicity guarantees  
under Conectiva Linux 9 kernel 2.4.x series with Linuxthreads. It could  
be just a problem with my development environment (which should not be  
since I am able to reproduce this problem under Mandriva Linux) but we  
should not rely on that but do take a safer approach right from the  
start.


Also, not all systems are fully POSIX compliant and the libs
should (I emphasize should over have to here :) do their best to  
produce similar behavior despite the environment differences.



Unfortunaly gnome.org is down at the moment so I cannot look up your
mailing
list references, but why is it that mutexes around the write call
don't solve
the issue (if in fact different threads within the same process do not

benefit from the POSIX atomicity guarantees)?  That should avoid
concurrent
writes to the Dispatcher pipe in every case.


	Okay, here is my theory from what I gathered from gdb. This is  
just a theory. Others more experienced with {glib,gtk}mm inner workings  
should know better. Well, under some irregular circunstances it is  
possible to lock up all threads (including the main thread and the  
controller thread for that matter) if a send_notification thread is  
preempted in the middle of it's execution while holding the lock. If  
the main/controller thread tries to use the send_notification (emit()),  
it will end up waiting on that mutex. Dead lock. Any way, even if this  
is not the case, I am experienced deadlocks with that approach.


	Well, it could be said that I have a flawed program design.  
However, we are doing it all by the book, mutexes on the dispatcher  
method receiver, etc. And, the program runs smoothly with the sleep  
trick.


void Dispatcher::emit()
{
   Glib::usleep(1000);
   notifier_-send_notification(this);
}

--
Mario

___
gtkmm-list mailing list
gtkmm-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtkmm-list