nanogui: Thread: multithreading issues


[<<] [<] Page 1 of 1 [>] [>>]
Subject: multithreading issues
From: ####@####.####
Date: 29 Aug 2007 14:58:45 +0100
Message-Id: <20070829085810.4mmuxhgxq84gsoog@localhost>

Hi,

Going through various emails from this list and experiments I'm trying  
to find a way to have one thread dealing with events and many other  
threads calling GrXXX functions. To my defense I can only say, that  
it's not me creating those threads, but some evil application  
programmers;) I'm just trying to provide the graphics framework based  
on nano-X.

The experiments have been conducted on an X86 with framebuffer support  
and microwindows from CVS and of course THREADSAFE=Y.

Here are my observations:

1.) There is a deadlock both with LINK_APP_INTO_SERVER and without.
Create a thread, which calls GrGetNextEvent() and tell it to listen  
only to keyboard events, but you never press any key.
GrGetNextEvent() takes a global lock and since select() never returns  
no other thread can draw at the same time, although I don't see any  
reason why this should be forbidden.
I propose two patches, which temporarily unlock the global lock in  
case there are no events in the event queue, i.e. select() is  
blocking, and lock it immediately after select().  (Please see files  
attached)

With those two patches both the case of Client/Server and  
LINK_APP_INTO_SERVER should be covered.

Greg, do you see any problems there?

2.) From what I saw the fun with multi threaded problems starts, when  
there are non void GrXXX functions called, which means, that the  
server needs to return something and its replies can get mixed up for  
the client threads.
The solution to this problem should be to use LINK_APP_INTO_SERVER, so  
there is no funny communication between client(s) and server, but  
there are direct function calls instead.

Greg, would you consider to use LINK_APP_INTO_SERVER and the attached  
patches as a safe approach for the described multi threading scenario?

Regards,
Robert







[Content type text/x-csrc not shown. Download]

[Content type text/x-csrc not shown. Download]
Subject: Re: [nanogui] multithreading issues
From: "Greg Haerr" ####@####.####
Date: 29 Aug 2007 20:14:34 +0100
Message-Id: <3e8e01c7ea70$b5a33fc0$0300a8c0@RDP>

> Going through various emails from this list and experiments I'm trying  
to find a way to have one thread dealing with events and many other  
threads calling GrXXX functions.

This can only work, even with your mod, only if you can guarantee
that no two threads will ever call a non-void GrXXX function
at once.  If the other threads only call void GrXXX (drawing only)
functions, this likely will work, since essentially the client->server
communications is write-only.

> With those two patches both the case of Client/Server and  
LINK_APP_INTO_SERVER should be covered.

At first glance, it seems OK, I need to think more deeply about
the locking mechanism and exactly when select() returns 0.

Can you send me your sample program that shows the system
not working until the patches are applied?

> 2.) From what I saw the fun with multi threaded problems starts, when  
there are non void GrXXX functions called, which means, that the  
server needs to return something and its replies can get mixed up for  
the client threads.
The solution to this problem should be to use LINK_APP_INTO_SERVER, so  
there is no funny communication between client(s) and server, but  
there are direct function calls instead.

I agree this is likely the answer, but the server will execute every
request on behalf of the calling thread, and that thread can't be
interrupted until the server's done processing it.  I'm not sure
this can be guaranteed without more thought.  Easier would be
to allow only non-voide Gr calls as discussed above. (perhaps we
need to put a list together of non-void drawing functions for
further analysis)

Regards,

Greg
Subject: Re: [nanogui] multithreading issues
From: ####@####.####
Date: 3 Sep 2007 15:43:01 +0100
Message-Id: <20070903094251.xrllncgo0kcw8kcg@localhost>

Hi Greg,

Sorry for the delay.
Now I revised my patches and added also an application, which shows  
the problem, as you requested and inlined it all in the mail instead  
of attachments to make your mailing list server more happy.

The non void nano-x calls are done from an init function (I want to  
change this later on)
Afterwards two threads are created. One, which handles the key pressed  
events and another one, which draws some stuff.

Here is the demo app:

---------->

#include <stdio.h>
#include <stdlib.h>
#define MWINCLUDECOLORS
#include "nano-X.h"
#include <pthread.h>

GR_WINDOW_ID wid;
GR_GC_ID gc;
GR_SCREEN_INFO	si;

void init();
void handle_events(GR_EVENT * event);
void handle_graphics();

void init()
{
         GrGetScreenInfo(&si);
	wid = GrNewWindow(GR_ROOT_WINDOW_ID, 0, 0, si.cols, si.rows, 1, GRAY, WHITE);
         GrSelectEvents(wid, GR_EVENT_MASK_KEY_DOWN);
	GrMapWindow(wid);

	gc = GrNewGC();
	GrSetGCForeground(gc, RED);
}

void handle_events(GR_EVENT * event)
{
         while (1)
	{
		printf("------------------------------------------------------\n");
		GrGetNextEvent(event);
		if(event != NULL)
		{
			switch (event->type)
			{
				case GR_EVENT_TYPE_KEY_DOWN:
					printf("KEY PRESSED \n");
					break;
			}
		}
		printf("------------------------------------------------------\n");
	}
}

void handle_graphics()
{
         int i;

	printf("Inside handle_graphics\n");

	for (i=1; i<10; i++)
	{
         	GrFillRect(wid, gc, 250-i*20, 230, 10, 50);
		GrFlush();
         	sleep(1);
         }
}

int main(int argc,char **argv) {
	GR_EVENT event;
	pthread_t  p_thread_events;
	pthread_t  p_thread_graphics;

	if (GrOpen() < 0) {
		fprintf(stderr,"cannot open graphics\n");
		exit(1);
	}

	init();
	pthread_create(&p_thread_events, NULL, (void *)handle_events, &event);
	pthread_create(&p_thread_graphics, NULL, (void *)handle_graphics, NULL);
	sleep(100);
	GrClose();
}


<----------

If I don't apply any patches, my system gets stuck (does not draw)  
because GrGetNextEvent() holds a lock an so the other thread can not  
draw.


Here are the patches:

---------------->

Index: microwin/src/nanox/client.c
===================================================================
--- microwin.orig/src/nanox/client.c
+++ microwin/src/nanox/client.c
@@ -989,8 +989,22 @@ _GrGetNextEventTimeout(GR_EVENT *ep, GR_
  		to.tv_usec = (timeout % 1000) * 1000;
  	}

-	if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL))>0) {
-		int fd;
+
+        /* --> */
+        /* replaced: */
+        /*
+        if((e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to :  
NULL))>0) {
+        */
+        /* with: */
+        /* give Nano-X calls from other threads a chance to run by  
releasing the lock */
+        UNLOCK(&nxGlobalLock);
+        e = select(setsize+1, &rfds, NULL, NULL, timeout ? &to : NULL);
+        /* we lock the GlobalLock again, which was unlocked a few  
lines above */
+        LOCK(&nxGlobalLock);
+        if(e>0)
+        {
+        /* <-- */
+                int fd;

  		if(FD_ISSET(nxSocket, &rfds)) {
  			/*

<-------------------

-------------------->

Index: microwin/src/nanox/srvmain.c
===================================================================
--- microwin.orig/src/nanox/srvmain.c
+++ microwin/src/nanox/srvmain.c
@@ -596,6 +596,7 @@ GsSelect(GR_TIMEOUT timeout)
  	int	setsize = 0;
  	struct timeval tout;
  	struct timeval *to;
+
  #if NONETWORK
  	int	fd;
  #endif
@@ -708,7 +709,25 @@ GsSelect(GR_TIMEOUT timeout)
  	}

  	/* Wait for some input on any of the fds in the set or a timeout: */
-	if((e = select(setsize+1, &rfds, NULL, NULL, to)) > 0) {
+
+	/* --> */
+        /* replaced: */
+        /*
+	if((e = select(setsize+1, &rfds, NULL, NULL, to)) > 0)
+        */
+        /* with: */
+#if NONETWORK
+        SERVER_UNLOCK();
+#endif
+        /* now we can call select, which will wait forever for an  
event to arrive */
+	e = select(setsize+1, &rfds, NULL, NULL, to);
+        /* we lock the GlobalLock again, which was unlocked a few  
lines above */
+#if NONETWORK
+        SERVER_LOCK();
+#endif
+        if(e>0)
+        /* <-- */
+        {
  		/* If data is present on the mouse fd, service it: */
  		if(mouse_fd >= 0 && FD_ISSET(mouse_fd, &rfds))
  			while(GsCheckMouseEvent())


<--------------------

With LINK_APP_INTO_SERVER, since all the Nano-X functions seem to  
reentrant, everything should work fine from multiple threads, as far  
as I can imagine.
It looks like the only communication, which is done through IPC is  
between e.g. mouse-server and keyboard-server.

Also the client/server approach should work, but I guess this needs  
some more thought about the protocol how the server replies to the  
client.

Also I noted, that because MW_FEATURE_TIMERS is enabled in srvmain.c  
select calls GdGetNextTimeout, which makes it timeout.

It looks like there is some CPU overhead by letting select time out  
due to this frequent polling. I guess it would be fine to let select  
only unblock in case there are new events coming in, or to increase  
the timeout for e.g. a screen saver.
I don't use timers from my application (for now), so do I really need this?

Regards,

Robert


[<<] [<] Page 1 of 1 [>] [>>]


Powered by ezmlm-browse 0.20.