["M.Stekelenburg" <root cal052304 student utwente nl>] Re: thread safe gtk?




[ Except for a detail or two, and for style, this is pretty much
  line-for-line identical to my gtkthreads-0.2. The most significant
  difference is that the condition variable is signaled at the
  end of gtk_thread_leave() instead of gtk_thread_enter(), which
  probably works better for the more typical light contention
  on the GTK lock. ]



(I think this will not get to the gtk-list because it is someone buffers
the list for me)

I've some code please try it, it might be the simple solution ;)

It is a replacement for Owens code except it is missing the
gtk_threads_enter_main and gtk_threads_leave_main.

Max

On 11 May 1998, Owen Taylor wrote:

> 
> Rob Browning <rlb@cs.utexas.edu> writes:
> 
> > I thought I'd forward this too since it's relevant to anyone following
> > this thread.  It's an improved way to handle the X pipe from Max.
> > 
> > ------- Start of forwarded message -------
> > Date: 	Sun, 10 May 1998 01:07:41 +0200 (MET DST)
> > From: "M.Stekelenburg" <root@cal052304.student.utwente.nl>
> > Reply-To: M.Stekelenburg@student.utwente.nl
> > To: Rob Browning <rlb@cs.utexas.edu>
> > Subject: Re: [gtk-list] Re: thread safe gtk?
> > Message-ID: <Pine.LNX.3.95q.980510010212.1128B-100000@noviomagus.student.utwente.nl>
> > MIME-Version: 1.0
> > Content-Type: TEXT/PLAIN; charset=US-ASCII
> > 
> > ok a better version of my code:
> > #define XOPEN write(Xpipe[1],"A",1);lock(xmutex);
> > #define XCLOSE signal(xthreadcond);unlock(xmutex);
> > 
> > the pipes etc remain the same but this also changes;
> > 
> > threadcall(){
> >   read(Xpipe[0],&c,1);
> >   wait(xthreadcond);
> > }
> > 
> > 
> > This use of threadconditions should make sure that control is transfered
> > from the gtk_main thread to the requesting and back.
> > 
> > But this construction is NOT tested.
> 
> I think if there are multiple threads trying to get the
> lock, a problem can happen:
> 
> - Subsidiary thread A tries to get the lock , so it writes  
>   to the pipe, then blocks on the lock.
> 
> - Subsidiary thread B tries to get the lock, so it writes
>   to the pipe, then blocks on the lock.
> 
> - Main thread M reads one byte from the pipe, then releases
>   the lock. and waits on the condition variable.
> 
> - thread A gets the lock, runs, signals the condition variable,
>   then release the lock.
> 
> - thread B gets the lock, runs, signals the condition variable,
>   then releases the lock.
> 
> - Main thread M gets the lock, goes back to the main loop,
>   sees there still is one byte in the pipe, releases the
>   lock and waits on the condition variable. But neither
>   A nor B wants the lock now, so the main loop hangs.
> 

your right the simple solution is reading the word at a different place
see the attachment. It now removes it request if it is honoured.


> There seems like there should be a simple solution to this,
> but I really couldn't figure one out. So what I did
> in "gtkthreads" was more complicated:
> 
> I kept a three-way state variable (unlocked, mainloop, locked),
> then as soon as a subsidiary thread wrote to the pipe,
> it changed the state from mainloop to locked so that future
> threads waiting on the lock would not try to do the same.
> 
> The state variable then has to be guarded by a mutex itself,
> so the main lock is no longer just a mutex, but is more 
> like a condpair. 
> 
> void
> gtk_threads_enter (void)
> {
>   pthread_mutex_lock (&gtk_lock_mutex);
> 
>   while (gtk_lock_state != GTK_UNLOCKED)
>     {
>       gtk_lock_nwaiting++;
>       if (gtk_lock_state == GTK_MAINLOOP)
> 	{
> 	  gtk_lock_state = GTK_LOCKED;
> 	  write(gtk_lock_pipe[1], "A", 1);
> 	}
>       pthread_cond_wait (&gtk_lock_cond, &gtk_lock_mutex);
>       gtk_lock_nwaiting--;
>     }
>   gtk_lock_state = GTK_LOCKED;
>   pthread_mutex_unlock (&gtk_lock_mutex);
> }
> 
> void
> gtk_threads_leave (void)
> {
>   pthread_mutex_lock (&gtk_lock_mutex);
>   gtk_lock_state = GTK_UNLOCKED;
>   pthread_cond_signal (&gtk_lock_cond);
>   pthread_mutex_unlock (&gtk_lock_mutex);
> }
> 
> As I said, it seems like there should be a simpler solution.
> 
> Regards,
>                                         Owen
> 
#include <pthread.h>
#include <gtk/gtk.h>
#include <unistd.h>
/*#define debug(x) printf(x);printf("\n");fflush(stdout); */
#define debug(x) 

pthread_cond_t Xcond  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t Xmutex= PTHREAD_MUTEX_INITIALIZER;
int Xpipe[2];

void gtk_threads_init(void) {
  pipe(Xpipe);
  pthread_mutex_lock(&Xmutex);  
}

/*this routine is called when something has written to the Xpipe*/

static void threadcall(void *a,int b,GdkInputCondition c) {
  debug("call"); 
  pthread_cond_wait(&Xcond,&Xmutex);
  debug("call 2"); 

}


gtk_threads_main(){
  gdk_input_add(Xpipe[0],GDK_INPUT_READ,threadcall,0);
  gtk_main();
}


/*
gtk_calls not made by the main thread should be wrapped between
gtk_thread_enter and gtk_thread_leave
*/
void gtk_threads_enter(){
  char c;
  debug("enter"); 
  write(Xpipe[1],"A",1);
  debug("enter 2"); 
  pthread_mutex_lock(&Xmutex);
  debug("enter 3"); 
  read(Xpipe[0],&c,1);  
  debug("enter 4"); 
}

void gtk_threads_leave(){
  debug("leave");
  pthread_cond_signal(&Xcond);
  debug("leave 2");
  pthread_mutex_unlock(&Xmutex);
  debug("leave 3");

}

gtk_thread_exit(){
  pthread_cond_destroy(&Xcond);
  pthread_mutex_destroy(&Xmutex);
  close(Xpipe[0]);
  close(Xpipe[1]);
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]