Article View: comp.os.os2
Article #1020Problem with multiple threads ...
From: Kai-Uwe Rommel
Date: Thu, 04 Jan 1990 17:41
Date: Thu, 04 Jan 1990 17:41
255 lines
7153 bytes
7153 bytes
Some time ago I posted my version of MicroEMACS 3.10 to this news group.
Of course it's not the best way to do the input from keyboard and mouse
with busy waiting. Now I tried to use two separate threads which wait
for keyboard and mouse input and write the characters to a global buffer
from which the main thread now reads his input.
For testing, I extracted all code related to this problem to a stand
alone program. The source is appended to this article. I do not have
much experience with multiple threads. Can someone please tell me if
something is wrong ?
The test program works but I have the following problems:
1. In checkmouse() you will find a call to MouReadEventQue() with
MOUSE_NOWAIT! When I use MOUSE_WAIT instead, I expect the thread to
sleep inside the call when no mouse input is available. But actually
THE OTHER (keyboard) thread is blocked and does not accept any input or
the main thread is blocked and cannot write to the screen. Why ?
As a workaround I use MOUSE_NOWAIT but only 10 times per second (the
DosSleep(100L) call !).
2. The KbdGetStatus() call (commented out) blocks the mouse thread when
the keyboard thread is waiting for input. Why ? I need the shift state
to create the mouse event characters correctly.
Except these two problems the serialization with the two semaphores
works well. But when I include the code into MicroEMACS other problems
arise which do no occur with the stand alone model (yes, the correct
compiling and linking options and libraries were used):
3. The whole editor blocks until I insert a DosSleepCall(10L) into the
keyboard thread loop too. When I trace the program with the debugger,
everything works well even without the DosSleep(10L).
4. When the mouse thread got an event he is blocked before he could
insert the event into the global buffer. Again, when I trace the threads
with the debugger, everything works well.
I already tried DosSetPrty(PRTYS_THREAD, PRTYC_IDLETIME, 0, threadid)
calls to reduce the priority of the waiting threads - no change.
What am I doing wrong ?
Chris Adie suggested another solution using a semaphore for the mouse
thread and another for the keyboard thread and a DosMuxSemWait() in the
main thread. But I want the kbd and mouse threads to run independently
and writing their input to the global buffer because this buffer then
serves as a typeahead buffer.
Kai Uwe Rommel
Munich
rommel@lan.informatik.tu-muenchen.dbp.de
------------------------------------------------------------
#include <stdio.h>
#include <process.h>
#include <stdlib.h>
#define INCL_BASE
#define INCL_NOPM
#include <os2.h>
#include <conio.h>
#define KEYBUFSIZE 64
#define THREADSTACK 4096
static int mouseflag = 0;
static HMOU hmouse;
static USHORT mousemask;
static int buttonmask[3] = {MOUSE_BN1_DOWN, MOUSE_BN3_DOWN, MOUSE_BN2_DOWN};
static USHORT in_buf[KEYBUFSIZE], in_next, in_last;
static void *kbd_stack, *mouse_stack;
static ULONG semAccess = 0L, semEmpty = 0L;
void in_init(void) /* initialize the input buffer */
{
DosSemRequest(&semAccess, SEM_INDEFINITE_WAIT);
DosSemSet(&semEmpty);
in_next = in_last = 0;
DosSemClear(&semAccess);
}
int in_check(void) /* is the input buffer non-empty? */
{
int empty;
DosSemRequest(&semAccess, SEM_INDEFINITE_WAIT);
empty = (in_next == in_last);
DosSemClear(&semAccess);
return !empty;
}
void in_put(int event)
{
DosSemRequest(&semAccess, SEM_INDEFINITE_WAIT);
in_buf[in_last++] = event;
in_last &= (KEYBUFSIZE - 1);
DosSemClear(&semEmpty);
DosSemClear(&semAccess);
}
int in_get(void) /* get an event from the input buffer */
{
int event; /* event to return */
DosSemWait(&semEmpty, SEM_INDEFINITE_WAIT);
DosSemRequest(&semAccess, SEM_INDEFINITE_WAIT);
event = in_buf[in_next++];
in_next &= (KEYBUFSIZE - 1);
if (in_next == in_last)
DosSemSet(&semEmpty);
DosSemClear(&semAccess);
return(event);
}
void checkmouse(void *arg)
{
MOUEVENTINFO mouInfo;
KBDINFO kbdInfo;
USHORT wait, old, new, cnt, chr;
while (1)
{
wait = MOU_NOWAIT;
MouReadEventQue(&mouInfo, &wait, hmouse);
if ( mouInfo.time != 0L )
{
kbdInfo.cb = sizeof(kbdInfo);
/* KbdGetStatus(&kbdInfo, 0); */
chr = 'a';
if ( kbdInfo.fsState & (LEFTSHIFT | RIGHTSHIFT) )
chr = 'A';
if ( kbdInfo.fsState & CONTROL )
chr = 'A' - '@';
for ( cnt = 0; cnt < 3; cnt++ )
{
old = mousemask & buttonmask[cnt];
new = mouInfo.fs & buttonmask[cnt];
if ( old != new )
{
in_put(0);
in_put(0x8000);
in_put(mouInfo.col);
in_put(mouInfo.row);
in_put(new ? chr + 2 * cnt : chr + 2 * cnt + 1);
}
}
mousemask = mouInfo.fs;
}
DosSleep(100L);
}
}
void checkkbd(void *arg)
{
KBDKEYINFO keyInfo;
USHORT nextc;
while (1)
{
KbdCharIn(&keyInfo, IO_WAIT, 0);
if (keyInfo.chChar == 0 || keyInfo.chChar == 0xE0)
{
nextc = keyInfo.chScan;
in_put(0);
in_put(nextc >> 8); /* prefix byte */
in_put(nextc & 255); /* event code byte */
}
else
in_put(keyInfo.chChar);
/* DosSleep(10L); */
}
}
int get(void)
{
NOPTRRECT rect;
USHORT res;
if ( in_check() )
return in_get();
if ( mouseflag )
MouDrawPtr(hmouse);
res = in_get();
if ( mouseflag )
{
rect.row = rect.col = 0;
rect.cRow = 24;
rect.cCol = 79;
MouRemovePtr(&rect, hmouse);
}
return res;
}
void main(void)
{
USHORT mask, key;
in_init();
if ( (kbd_stack = malloc(THREADSTACK)) == NULL ||
(mouse_stack = malloc(THREADSTACK)) == NULL )
{
puts("Cannot allocate thread stacks.");
exit(-1);
}
MouOpen(NULL, &hmouse);
mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN;
MouSetEventMask(&mask, hmouse);
mask = 0;
MouSetDevStatus(&mask, hmouse);
_beginthread(checkmouse, mouse_stack, THREADSTACK, NULL);
_beginthread(checkkbd, kbd_stack, THREADSTACK, NULL);
do
{
key = get();
printf("Empty=%08lx Access=%08lx in_next=%d in_last=%d %04x\n",
semEmpty, semAccess, in_next, in_last, key);
}
while (key != 27);
exit(0);
}
Technical Details
Message-ID:
<1028@tuminfo1.lan.informatik.tu-muenchen.dbp.de>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!aplcen!uakari.primate.wisc.edu!zaphod.mps.ohio-state.edu!mips!apple!snorkelwacker!bloom-beacon!eru!luth!sunic!mcsun!unido!fauern!tumuc!lan!rommelShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!aplcen!uakari.primate.wisc.edu!zaphod.mps.ohio-state.edu!mips!apple!snorkelwacker!bloom-beacon!eru!luth!sunic!mcsun!unido!fauern!tumuc!lan!rommel From: rommel@lan.informatik.tu-muenchen.dbp.de (Kai-Uwe Rommel) Newsgroups: comp.os.os2 Subject: Problem with multiple threads ... Message-ID: <1028@tuminfo1.lan.informatik.tu-muenchen.dbp.de> Date: 4 Jan 90 17:41:48 GMT Sender: news@lan.informatik.tu-muenchen.dbp.de Reply-To: rommel@lan.informatik.tu-muenchen.dbp.de (Kai-Uwe Rommel) Distribution: comp.os.os2 Organization: Inst. fuer Informatik, TU Muenchen, W. Germany Lines: 255