duncanb@ibmpcug.co.uk (D G Booth) (03/12/91)
Christophe Wolfhugel asks whether OS/2 had any mechanism similar to the classic counting semaphores. There is no such mechanism built-in to OS/2, but I have used the code below quite successfully. The code defines a new structure type COUNTSEM which is a counting semaphore, and functions P and V that operate on it. P decrements the counter, but blocks if the counter is 0 until it is non-zero. V increments the counter (and unblocks any blocked threads). The code can be in an application managing mutual exclusion between threads. It may also be in a DLL to manage semaphores between processes, but in this case the MutualExclusion semaphore, and the COUNTSEM structures should all be put in shared memory. Duncan Booth <duncanb@ibmpcug.co.uk> ======= File: SEM.H ============ typedef struct COUNTSEM { long countSem; USHORT count; } COUNTSEM, far *PCOUNTSEM; void P (PCOUNTSEM s); /* Wait till non-zero then decrement. */ BOOL P_timeout (PCOUNTSEM s, LONG timeout); /* as P - may time out. */ void V (PCOUNTSEM s); /* Increment */ ======== End of SEM.H ========== ======= File: SEM.C ============ /* * Useful code using semaphores. * * Author: Duncan Booth */ #define INCL_DOSPROCESS #include <os2.h> #include "sem.h" /* * This semaphore is local to this file. It is used to control requests * to the counting semaphore structures. */ static long MutualExclusion = 0L; #define GET_SEM() (DosSemRequest (&MutualExclusion, SEM_INDEFINITE_WAIT)) #define RLS_SEM() (DosSemClear (&MutualExclusion)) void P (PCOUNTSEM s) { int blocked=1; while (blocked) { DosSemWait (&s->countSem, SEM_INDEFINITE_WAIT); /* wait til maybe ok */ GET_SEM(); if (s->count == 0) /* not ready yet */ DosSemSet (&s->countSem); /* set up block */ else { s->count--; /* decrement count */ blocked = 0; /* set up loop exit */ } RLS_SEM(); } } BOOL P_timeout (PCOUNTSEM s, LONG timeout) { int blocked=1; while (blocked == 1) { if (DosSemWait (&s->countSem, timeout) != 0) return FALSE; /* wait til maybe ok */ if (GET_SEM() != 0) return FALSE; if (s->count == 0) /* not ready yet */ DosSemSet (&s->countSem); /* set up block */ else { s->count--; /* decrement count */ blocked = 0; /* set up loop exit */ } RLS_SEM(); } return TRUE; } void V (PCOUNTSEM s) { GET_SEM(); /* mutual excl */ s->count++; /* increment count */ DosSemClear (&s->countSem); /* free waiters */ RLS_SEM(); /* mutual excl */ } ======== End of SEM.C ========== -- Automatic Disclaimer: The views expressed above are those of the author alone and may not represent the views of the IBM PC User Group. -- Duncan Booth, RCP Ltd. Didcot, Oxon, UK duncanb@ibmpcug.co.uk Bix: jrichards
kushner@ux1.lbl.gov (Gary Kushner) (04/08/91)
Your code uses polling which should be avoided if at all possible. Here is the code I use: ---------- pv.h: ---------- /*------------ Type for PVsems ------------*/ typedef struct _pvsem { long count; long more; // sem clear if count > 0 long mutex; } _far PVSEM; /*----------- Protos -----------*/ PVSEM _far *PVSemCreate(void); void _far _fastcall P(PVSEM _far *s); void _far _fastcall V(PVSEM _far *s); -------- pv.c --------- #define INCL_DOSSEMAPHORES #include <os2.h> #include <malloc.h> #include "pv.h" /************** * PVSEMCREATE - allocate sem **************/ PVSEM _far *PVSemCreate(void) { PVSEM *s; if ( (s=calloc(1, sizeof(PVSEM))) != NULL) s->count=0; return s; } /************** * P - **************/ void _far _fastcall P(PVSEM _far *s) { // any V's pending? if not then wait... DosSemRequest(&s->more, SEM_INDEFINITE_WAIT); DosSemRequest(&s->mutex, SEM_INDEFINITE_WAIT); // if there are still more V's, then leave more clear if (--(s->count) > 0) DosSemClear(&s->more); DosSemClear(&s->mutex); } /************** * V - count them up **************/ void _far _fastcall V(PVSEM _far *s) { DosSemRequest(&s->mutex, SEM_INDEFINITE_WAIT); s->count++; DosSemClear(&s->more); // ok guys, come and get it DosSemClear(&s->mutex); }