| TIP: Click on subject to list as thread! | ANSI |
| echo: | |
|---|---|
| to: | |
| from: | |
| date: | |
| subject: | DosRead blocking |
JRC> :) I understand. *sigh* Is there an alternative to using Mutex
JRC> semaphores? They seem to take a *LONG* time to lock/unlock (or is that
JRC> block/unblock). I recall seeing some code that used
JRC> the DosEnterCritSec
Forget that function exists.
IBM's compiler has a great set of undocumented semaphore functions (or you
can roll your own, but you _must_ use a little assembly language for the
LOCK prefix (to make it SMP safe)).
These type of semaphores use a local flag to keep a lock count (and this is
the flag that requires the intel LOCK prefix). Only when the lock count is
greater than zero, does the "fast semaphore" code call an OS/2
sem api to handle it (You want to call an OS/2 api here, and not your own
"wait" function, so that the os/2 schedular can do its magic).
Rolling your own code for this was easy under OS/2 1.x, but got a little
complicated under OS/2 2.x (because you have to use two types of
semahpores).
The reasoning is: Since a collision is rare, especially when you only
have one cpu, why call DosSem function every time?
Avoid the call by keeping a local flag indicating
whether or not a collision has taken place.
DosEnterCritSec() is the other extreme; it assumes
every thread in your program has collided (asked for
access to the same resource) at the same time, even
if the other threads never use it!
A "fast semaphore" is faster than DosEnterCritSec()
anyway.
Here's an old note I wrote:
Recently, someone was inquiring about the "fast semaphores" that the
IBM Cset++ runtime library uses internally. These sems _are_ SMP
safe. I was able to hack this (use at your own risk; as long as you
keep the Open/Request/Relase/Close paradigm, you can easily write the
code for the real OS/2 api's if things go wrong, or the semaphore api
for any OS; think of this as the start of your portable semaphore API
library).
#include
#include
#include
#include
#include
#define INCL_NOPMAPI
#define INCL_DOS
#include
typedef struct _fastsem {
long cnt;
long hev;
long hmtx;
}FASTSEM;
#if 1
int _CreateSem(FASTSEM *, int StateOwned);
int _RequestSem(FASTSEM *);
int _ReleaseSem(FASTSEM *);
int _CloseSem(FASTSEM *);
#else // use these to see it fail:
#define _CreateSem(x, y) 0
#define _RequestSem(x) 0
#define _ReleaseSem(x) 0
#define _CloseSem(x) 0
#endif
static FASTSEM gFSem;
static volatile int flag = 0;
void Thread2(void *ignore)
{
int rc;
for(;;){
rc = _RequestSem(&gFSem);
assert(!flag); // if flag is set, there was a collision
flag++;
if(rc){
printf("error %d from _ReQuestSem\n", rc);
exit(1);
}
DosSleep(0L);
flag--;
rc = _ReleaseSem(&gFSem);
if(rc){
printf("error %d from _ReleaseSem\n", rc);
exit(1);
}
printf("Thread %d had it\n", *_threadid);
}
}
int main(void)
{
int rc;
rc = _CreateSem(&gFSem, 0);
if(rc){
printf("error %d from _CreatSem\n", rc);
exit(1);
}
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
getchar();
}
Bench Test
==========
A program was written to Request/Release a semaphore 500,000 times. Three
types of sems were tested:
1) 16 Bit OS/2 1.x Ram Semaphores
2) 32 bit anonymous mutex sempahorees
3) The Cset++ 2.1 fast semaphores.
Results (time in milliseconds; faster is better)
================================================
16 bit (running under OS/2 1.x) : 6125
16 bit (running under OS/2 2.x) : 3281
32 bit mutex : 11937
32 bit cset : 1000
All of these sems are fast, considering the number of iterations.
For IBM VA C++ 3.0 -- not 100% confident
========================================
Changes: _CreateSem() has a new parameter (possibly a semaphore name,
as there is a new function called _OpenSem() that takes a name).
The "FASTSEM" structure has changed, and is of unknown size -- it may
even be smaller than before, since a 'htmx' is no longer used.
typedef struct _fastsem {
char x[16];
}FASTSEM;
#if 1
int _CreateSem(FASTSEM *, int unKnown, int StateOwned);
int _RequestSem(FASTSEM *);
int _ReleaseSem(FASTSEM *);
int _CloseSem(FASTSEM *);
#else // use these to see it fail:
#define _CreateSem(x, y, z) 0
#define _RequestSem(x) 0
#define _ReleaseSem(x) 0
#define _CloseSem(x) 0
#endif
static FASTSEM gFSem;
static volatile int flag = 0;
void _Optlink Thread2(void *ignore)
{
int rc;
for(;;){
rc = _RequestSem(&gFSem);
assert(!flag); // if flag is set, there was a collision
flag++;
if(rc){
printf("error %d from _ReQuestSem\n", rc);
exit(1);
}
DosSleep(0L); // provide a window for failure.
flag--;
rc = _ReleaseSem(&gFSem);
if(rc){
printf("error %d from _ReleaseSem\n", rc);
exit(1);
}
printf("Thread %d had it\n", *_threadid);
DosSleep(0L);
}
}
int main(void)
{
int rc;
setvbuf(stdout, NULL, _IONBF, 0);
rc = _CreateSem(&gFSem, 0, 1);
if(rc){
printf("error %d from _CreatSem\n", rc);
exit(1);
}
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
_beginthread(Thread2, NULL, 0x2000, NULL);
printf("press enter to release sem from thread 1\n");
getchar();
rc = _ReleaseSem(&gFSem);
if(rc){
printf("error %d from _ReleaseSem\n", rc);
exit(1);
}
printf("Thread %d had it\n", *_threadid);
printf("press enter to end pgm\n");
getchar();
}
--- Maximus/2 2.01
SEEN-BY: 259/414
------------------------------------------------------------------------------
Area 62, Msg#1470, Feb-16-96 09:39:46
From: jeroenj{at}ibm.net
To: All
Subject: Re: Implementing Fast Ram Semaphores
From: jeroenj{at}ibm.net
Newsgroups: comp.os.os2.programmer.misc
Subject: Re: Implementing Fast Ram Semaphores
In , jimh{at}hilgraeve.com (Jim Harmer) writes:
>A couple of weeks ago, I saw the __?xchg functions mentioned
> [...]
>create Fast Ram Semaphores, which could intern be used to
> [...]
> - If so how did you set it up?
In pseudocode:
volatile int isSet, sleeping;
inline void lock () { while (xchg (&isSet, 1)) sleep (); }
inline void unlock () { isSet = 0; if (sleeping) wakeup (); }
void sleep () { DosResetEventSem (); sleeping = True; DosWaitEventSem (); }
void wakeup () { sleeping = False; DosPostEventSem (); }
In this scheme a thread will not obtain an OS/2 semaphore unless there is a
chance
that another thread owns the semaphore.
> - We currently use Mutex Semaphores, do you think this
> would be faster or should we stick with the mux?
Fast Ram semaphores are very much faster. We got an performance boost
in the order of magnitude of 10-20% *only* by using these semaphores
(our memory management has been made reentrant using these).
Hope this helps.
------------------------------------------------------------------------------
--- Maximus/2 3.00
* Origin: Sol 3 * Toronto * V.32 * (905)858-8488 (1:259/414)* Origin: Sol 3 * Toronto * V.32 * (905)858-8488 (1:259/414) SEEN-BY: 50/99 54/99 270/101 620/243 625/0 160 711/401 409 410 413 430 808 SEEN-BY: 711/809 934 955 712/311 407 505 506 517 623 624 704 841 713/317 SEEN-BY: 800/1 @PATH: 259/414 99 2424/38 11 10 396/1 270/101 712/624 711/808 934 |
|
| SOURCE: echomail via fidonet.ozzmosis.com | |
Email questions or comments to sysop@ipingthereforeiam.com
All parts of this website painstakingly hand-crafted in the U.S.A.!
IPTIA BBS/MUD/Terminal/Game Server List, © 2025 IPTIA Consulting™.