[comp.os.os2.programmer] Making a non exclusive semaphore

wolf@grasp1.univ-lyon1.fr (Christophe Wolfhugel) (03/10/91)

Is there any mechanisme similar to Unixes' semaphores, ie I'd like to get
a semaphore with units: 
  - one thread increments it (so never blocking)
  - another thread uses units and gets blocked only when the counter is 0.
(it's for managing a packet layer window in a comm package).

-- 
Christophe Wolfhugel (on irc: Zolf)   |  Email: wolf@grasp1.univ-lyon1.fr
Listserv admin at fifi.univ-lyon1.fr  |  Fax:   (+33) 72 44 08 00

wbonner@eecs.wsu.edu (Wim Bonner) (03/12/91)

In article <18131@milton.u.washington.edu> wolf@grasp1.univ-lyon1.fr (Christophe Wolfhugel) writes:
>Is there any mechanisme similar to Unixes' semaphores, ie I'd like to get
>a semaphore with units: 
>  - one thread increments it (so never blocking)
>  - another thread uses units and gets blocked only when the counter is 0.
>(it's for managing a packet layer window in a comm package).

I know that when you use semaphores in OS/2, they are not really sspecified as
to the way they are impleneted internally, but a DosSemWait will wait for the 
semaphore to be completely cleared.  (Multple DosSemSet()'s seem to increment 
the counter, and you must use the same number of DosSemClear()'s to get the
semaphore back to the original state.)  A DosSemRequest will wait till the 
sem has been cleared, and then set it.

Hope this helps...
-- 
|  wbonner@yoda.eecs.wsu.edu  |
| 27313853@wsuvm1.csc.wsu.edu |
|  72561.3135@CompuServe.com  |

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);
}