Threads continued ...

From: Marc Hemberger (hemberg@clri6a.gsi.de)
Date: Tue Aug 24 1999 - 16:59:49 MEST


Dear ROOTers,

we continued our investigations on the usage of threads within ROOT (see
http://www-wnt.gsi.de/go4/Threads/tthread.htm) and found some interesting
behaviour. 

Using the TThread classes provided in the framework of ROOT (e.g. 2.22),
we found, that on our working environment here at GSI (Linux Debian 2.1,
kernel 2.0.36, glibc 2.0, XFree 3.3.2 on SMP machines with two CPUs) all
actions on the TCanvas from within threads causes nearly instantaniously a
segmentation violation.

Having also access to single CPU machines we found, that the identical
program (which starts several threads and each accesses the canvas) works!

Thus the mechanism provided by ROOT to protect the canvas from accesses by
different threads at the same time works in principle, but there seems to
be a problem in the interplay between ROOT and the Xlib. Since the X11R6
is stated to be thread-safe, we wanted now to check on the experimental
SMP-support in the kernel in use.

So I created a simple C-program, based only on calls to the Xlib and to
the pthreads, which reproduces the error on SMP-machines but runs on
single-CPU machines.

We would greatly appreciate any help from anybody outside, who has access
to an SMP-machine with a newer kernel (like 2.2.x). Just compile the
attached program on your machine and try wether it runs stable, also
introducing different timing values (by the sleep/usleep). Any response to
that problem is greatly appreciated. 

We try currently to draw our conclusions from the findings we have here
about the use of threads within our GO4 project.

Greetings,

Marc


----------------------------------------
Dr. Marc Hemberger

GSI, Abteilung DV&EE
Planckstr. 1
64291 Darmstadt

M.Hemberger@gsi.de




/* X lib program with multithreading,
   the timing introduced by the sleep/usleep commands is essential for the
   program
   */
   
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/keysym.h>

#include <math.h>
#include <pthread.h>
#define EXIT_FAILURE 1
pthread_t tid1, tid2, tid3;
pthread_attr_t t_attr;
pthread_mutex_t mut1;
pthread_mutexattr_t attr;
int counter=0;
Bool propagate = False;

Display *display;  /* Server or display to which a connection will be made */
int screen;        /* Screen number to use on that display */
Window win;        /* The applications one and only window */
XEvent event;      /* The event data structure */
GC gc1, gc2;       /* Graphics context data structures */
XGCValues gs1,gs2; /* Graphics context settings */
char *message;     /* Message printed in window */
char mess[] = { "000000000" };
static char progDefaultMessage[] = {"A Simple Xlib Program"};

extern int counter;

void setUpGCs();
void drawInToWindow();
void drawCountWindow();
void thread1();
void thread2();
void thread3();
void threadex();

int main(argc, argv)
    int argc; char **argv;
{
  int count, *rc;
  /* Attempt to connect to the server and use the default screen */
  if ((display = XOpenDisplay(NULL)) == NULL) {
    perror("Can't connect to server");
    exit(1);
  }
  screen = DefaultScreen(display);

  /* Create a window */
  win = XCreateSimpleWindow(display, RootWindow(display, screen),
			    100, 200, 400, 300, 1, BlackPixel(display, screen),
			    WhitePixel(display, screen));
  
  /* Set up which event types the window will handle */
  XSelectInput(display, win, ExposureMask | ButtonPressMask);
  
  /* Graphics contexts */
  setUpGCs();
  
  /* Attempt to get message from user-defined resource setting */
  if ((message = XGetDefault(display, "win", "message")) == NULL)
    message = progDefaultMessage;
  
  /* Map the window in order for it to be displayed */
  XMapWindow(display, win);

  threadex();
  
  /* Enter an infinite loop, awaiting and responding to the chosen events */
  count = 0;
  while (1) {
    XNextEvent(display, &event);
    switch (event.type) {
    case Expose: drawInToWindow(); break; /* Draw/re-draw everything */
    case ButtonPress: exit(0); break; /* Quit on mouse button press */
    default: break;
    }
    if(counter > 99999)
      {
	if(pthread_mutex_lock(&mut1) == -1) {
	  perror("pthread_mutex_lock");
	  exit(EXIT_FAILURE);
	}
	counter = 0;
	count ++;
	if(pthread_mutex_unlock(&mut1) == -1) {
	  perror("pthread_mutex_unlock");
	  exit(EXIT_FAILURE);
	}
	fprintf(stderr, "counter reset %d\n", count); 
      }
  }
}

void setUpGCs()
    /* Set up 2 graphics context resources in the display server */
    /* gc1 for message and rectangle; gc2 for ellipse */
{
  /* Define a bitmap for the stipple pattern used to fill the ellipse */
#define stipple_width 3
#define stipple_height 3
  static char stipple_bits[] = {0x02, 0x05, 0x02};
  Pixmap stipple;
  
  /* Create the stipple for ellipse fill pattern of gc2 */
  if ((stipple = XCreateBitmapFromData(display, RootWindow(display, screen),
				       stipple_bits, stipple_width, stipple_height)) == 0) {
    perror("Can't create bitmap");
    exit(1);
  }
  
  gc1 = XCreateGC(display, win, 0, &gs1); /* 0 -> use defaults */
  gc2 = XCreateGC(display, win, 0, &gs2); /* 0 -> use defaults */
  /* Now override some of the defaults */
  XSetForeground(display, gc1, BlackPixel(display, screen));
  XSetBackground(display, gc1, WhitePixel(display, screen));
  XSetLineAttributes(display, gc1, 2, LineSolid, CapRound, JoinRound);
  XSetStipple(display, gc2, stipple);
  XSetFillStyle(display, gc2, FillOpaqueStippled);
}

void drawInToWindow()
{
  /* Print message, draw restangle and filled ellipse as defined */
  /* by the GC */
  XDrawString(display, win, gc1, 130, 20, message, strlen(message));
  XDrawRectangle(display, win, gc1, 40, 40, 320, 220);
  XFillArc(display, win, gc2, 50, 50, 300, 200, 0, 360*64);
}

void drawCountWindow()
{
  XSendEvent(display, win, propagate, ExposureMask, &event);
}

void thread1()
{
  static int count = 0;
  while(1) {
    if(pthread_mutex_lock(&mut1) == -1) {
      perror("pthread_mutex_lock");
      exit(EXIT_FAILURE);
    }
    count++;
    counter = counter + 1;
    /* fprintf(stderr, "T1=%02d %02d ", counter, count); */
    if(pthread_mutex_unlock(&mut1) == -1) {
      perror("pthread_mutex_unlock");
      exit(EXIT_FAILURE);
    }
    XFillRectangle(display, win, gc1, 308, 8, 50, 15);
    sprintf(mess, "%s %05d", "T1", counter);
    XSetForeground(display, gc1, WhitePixel(display, screen));
    XDrawString(display, win, gc1, 310, 20, mess, strlen(mess));
    XSetForeground(display, gc1, BlackPixel(display, screen));
    XSendEvent(display, win, propagate, ExposureMask, &event);
    sleep(1);                         /* <======= introduce tming here! */
    /* usleep(100000); *//* <== this does not work !! */
  }
}

void thread2()
{
  static int count = 0;
  while(1) {
    if(pthread_mutex_lock(&mut1) == -1) {
      perror("pthread_mutex_lock");
      exit(EXIT_FAILURE);
    }
    count++;
    counter = counter + 1;
    /* fprintf(stderr, "\tT2=%02d %02d ", counter, count); */
    if(pthread_mutex_unlock(&mut1) == -1) {
      perror("pthread_mutex_unlock");
      exit(EXIT_FAILURE);
    }
    XFillRectangle(display, win, gc1, 48, 8, 50, 15);
    sprintf(mess, "%s %05d", "T2", counter);
    XSetForeground(display, gc1, WhitePixel(display, screen));
    XDrawString(display, win, gc1, 50, 20, mess, strlen(mess));
    XSetForeground(display, gc1, BlackPixel(display, screen));
    XSendEvent(display, win, propagate, ExposureMask, &event);
    usleep(378000);                  /* <======= introduce tming here! */
    /* usleep(200000); *//* <== this does not work !! */
  }
}

void thread3()
{
  static int count = 0;
  while(1) {
    if(pthread_mutex_lock(&mut1) == -1) {
      perror("pthread_mutex_lock");
      exit(EXIT_FAILURE);
    }
    count++;
    counter = counter + 1;
    /* fprintf(stderr, "\tT3=%02d %02d ", counter, count); */
    if(pthread_mutex_unlock(&mut1) == -1) {
      perror("pthread_mutex_unlock");
      exit(EXIT_FAILURE);
    }
    XSendEvent(display, win, propagate, ExposureMask, &event);
    usleep(734000);                /* <======= introduce tming here! */
    /* usleep(150000); */ /* <== this does not work !! */
  }
}

void threadex()
{
  if(pthread_mutexattr_init(&attr) == -1) {
    perror("pthread_mutexattr_create");
    exit(EXIT_FAILURE);
  }
  if(pthread_mutex_init(&mut1, &attr) == -1) {
    perror("pthread_mutex_init");
    exit(EXIT_FAILURE);
  }
  if(pthread_attr_init(&t_attr) == -1) {
    perror("pthread_attr_create");
    exit(EXIT_FAILURE);
  }
  if(pthread_create(&tid1, &t_attr, thread1, 0) == -1) {
    perror("pthread_create(1)");
    exit(EXIT_FAILURE);
  }
  if(pthread_create(&tid2, &t_attr, thread2, 0) == -1) {
    perror("pthread_create(2)");
    exit(EXIT_FAILURE);
  }
  if(pthread_create(&tid3, &t_attr, thread3, 0) == -1) {
    perror("pthread_create(3)");
    exit(EXIT_FAILURE);
  }
    
  /*
     for(;;)
     pause();
  */
}


# ========================= Ultrix: ===========================
#
   CC      = egcc
   O       = o
# To enable debugging use '-g' option for compile step:
#  CFLAGS  = -g -D_CFORTRAN2_VERSION_ -gen_feedback 
#  CFLAGS  = -g -D__STDC__ -Dconst=" " -D__LANGUAGE_C -D__mips -DDEBUG
   CFLAGS  = -Wall -O3
# cc CFLAGS = -w0 -O3 or -g0 -g1 -g2 -g3  on levi
# To enable profiling use '-p' option for link step:
#   LFLAGS  = -p1 -pg
#   LFLAGS  = -Wl,-yprob_
   LFLAGS  = 
   LINK    = egcc
   OUTPUT  = -o ### The blank before the '#' is required!
   MATHLIB = -lm
   EXE     =
   LIB     = a
   F77COMP = g77 -c
   F77     = g77
   FFLAGS  = -static -g -warn unused -O3
#  for profiling enable -g3
#   FFLAGS  = -static -g -g3

# Symbols for linking with libraries:

#   FPLIB = -L/us0/vlk/hemberg/fpack -lfpack08604
#   CERNLIB = -L/cern/pro/lib -lkernlib -lpacklib \
#             -lUfor -lfor -lFutil -lm -lots -lc
   XLIB = -L/usr/X11/lib -lX11 -lXm -lXaw -lXp -lXpm
   VOGLLIB= -L/u/hemberg/ftp/vogle-3.0/src -lvogle
#   MIZZILIB= -L/us0/vlk/hemberg/ccl -lccl
   DIVLIB= -lpthread
   GRAFLIB= -L/cern/pro/lib -lgraflib -lgrafX11 
#   PGPLOT= -lcpgplot -lpgplot
   MATHLIB = -lm
   CPPLIB = -lstdc++

winthread2$(EXE): winthread2.$(O)
	$(LINK) $(LFLAGS) winthread2.$(O) $(DIVLIB) $(XLIB) $(OUTPUT) winthread2

winthread2.$(O): winthread2.c



This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:43:38 MET