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: jrichardskushner@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);
}