XForms: More on the subject of threads

From: Steve Lamont (spl@blinky.ucsd.edu)
Date: Fri Jun 02 2000 - 11:02:48 EDT

  • Next message: Steve Lamont: "Re: XForms: widgets"

    # To subscribers of the xforms list from Steve Lamont <spl@blinky.ucsd.edu> :

    I did some reading and research, digging briefly into the innards of
    XForms, and may have a potential workaround for the lack of direct
    threads support in XForms.

    The major problem lies in the fact that asynchronous events (button
    clicks, etc.) can bollix up the works if some thread is attempting to
    update a form.

    I may have a workaround which eventually, with embellishments, should
    probably get folded into XForms. That is to replace the XForms main
    loop, fl_do_forms() with

            EXTERN pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
            
               [...]
            
               while ( 1 ) {
            
                   pthread_mutex_lock( &mutex );
                   fl_check_forms();
                   pthread_mutex_unlock( &mutex );
                   /* you may need to sleep here to give up the CPU to */
                   /* the concurrent threads */

               }

    Any thread that makes an XForms call should do

                    pthread_mutex_lock( &mutex );
                    fl_whatever( ... );
                    pthread_mutex_unlock( &mutex );
            
    Callbacks do not need to set a mutex lock since they're already in a
    mutex -- they're called by fl_check_forms().

    The following rather simpleminded application should be a useful
    illustration of how this can be done.

    I compiled it on Solaris 8 with

            gcc -fpcc-struct-return try.c -o try \
                    -L/usr/openwin/lib -lforms -lXpm -lXext -lX11 \
                    -lpthread -lm

    I've been running it while composing this email (probably about 20
    minutes -- I write slowly) with nary a hiccough.

                                    - - -
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>

    #include <pthread.h>

    #include "forms.h"

    extern void click_cb(FL_OBJECT *, long);

    typedef struct {
            FL_FORM *try;
            void *vdata;
            char *cdata;
            long ldata;
            FL_OBJECT *b[4];
    } FD_try;

    extern FD_try * create_form_try(void);

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    FD_try *fd_try;

    void click_cb( FL_OBJECT *ob, long data )

    {
            
        FD_try *fd_try = ( FD_try *) ob->form->fdui;
        int whatever_button = lrand48() % 4;

        /* No mutex needed here */
          
        fl_set_button( fd_try->b[whatever_button],
                       !fl_get_button( fd_try->b[whatever_button] ) );

    }

    void *do_stuff( void *arg )

    {

        while ( 1 ) {

            struct timeval sleepy_time;
            int random_button = lrand48() % 4; /* Pick a random button */

            /* Wait some random time */

            sleepy_time.tv_sec = 0;
            sleepy_time.tv_usec = lrand48() % 100000; /* 10 msec max */
            select( 0, NULL, NULL, NULL, &sleepy_time );

            pthread_mutex_lock( &mutex ); { /* critical section */

                fl_set_button( fd_try->b[random_button],
                               !fl_get_button( fd_try->b[random_button] ) );

            } pthread_mutex_unlock( &mutex );

        }

    }
            
    int main(int argc, char *argv[])

    {

        int i;
        pthread_t pthread_id;
        
        XInitThreads(); /* Make Xlib happy -- this must be called */
                                    /* before any other Xlib calls. Requires */
                                    /* X11R6 */

        fl_initialize( &argc, argv, 0, 0, 0 );
        
        fd_try = create_form_try();

        fl_show_form( fd_try->try,
                      FL_PLACE_CENTERFREE,
                      FL_FULLBORDER,
                      "try" );
        
        thr_setconcurrency( 5 ); /* A Solaris thing -- other systems will */
                                    /* probably require pthread_setconcurrency() */
        
        for ( i = 0; i < 4; i++ ) { /* Launch the threads */
            
            pthread_attr_t attr;
            
            pthread_attr_init( &attr );
            pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
            
            pthread_create( &pthread_id, &attr, do_stuff, NULL );
            
            pthread_attr_destroy( &attr );
            
        }
        
        /* Replace fl_do_forms() */

        while ( 1 ) {
            
            struct timeval sleepy_time;

            /* Give up the CPU for 10 milliseconds */

            sleepy_time.tv_sec = 0;
            sleepy_time.tv_usec = 10000
            select( 0, NULL, NULL, NULL, &sleepy_time );

            pthread_mutex_lock( &mutex ); { /* Critial section */
                
                fl_check_forms();
                
            } pthread_mutex_unlock( &mutex );
            
        }
        
        return 0;
        
    }

    FD_try *create_form_try(void)

    {

        FL_OBJECT *obj;
        FD_try *fdui = (FD_try *) fl_calloc(1, sizeof(*fdui));
        
        fdui->try = fl_bgn_form(FL_NO_BOX, 150, 230);
        obj = fl_add_box(FL_EMBOSSED_BOX,0,0,150,230,"");
        fl_set_object_color(obj,FL_LEFT_BCOL,FL_COL1);
        obj = fl_add_button(FL_NORMAL_BUTTON,20,20,110,40,"Click Me");
        fl_set_object_callback(obj,click_cb,0);
        fdui->b[0] = obj =
            fl_add_lightbutton(FL_PUSH_BUTTON,25,80,105,25,"Button 1");
        fl_set_object_boxtype(obj,FL_NO_BOX);
        fdui->b[1] = obj =
            fl_add_lightbutton(FL_PUSH_BUTTON,25,115,105,25,"Button 2");
        fl_set_object_boxtype(obj,FL_NO_BOX);
        fdui->b[3] = obj =
            fl_add_lightbutton(FL_PUSH_BUTTON,25,185,105,25,"Button 4");
        fl_set_object_boxtype(obj,FL_NO_BOX);
        fdui->b[2] = obj =
            fl_add_lightbutton(FL_PUSH_BUTTON,25,150,105,25,"Button 3");
        fl_set_object_boxtype(obj,FL_NO_BOX);
        fl_end_form();
        
        fl_adjust_form_size(fdui->try);
        fdui->try->fdui = fdui;

        return fdui;
    }
                                    - - -

                                                            spl
    _________________________________________________
    To unsubscribe, send the message "unsubscribe" to
    xforms-request@bob.usuhs.mil or see
    http://bob.usuhs.mil/mailserv/xforms.html
    XForms Home Page: http://world.std.com/~xforms
    List Archive: http://bob.usuhs.mil/mailserv/list-archives/



    This archive was generated by hypermail 2b29 : Fri Jun 02 2000 - 11:07:32 EDT