You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bounce.c is a sample multithread program that creates a new thread each time the letter a or A is typed. Each thread bounces a happy face of a different color around the screen. Up to 32 threads can be created. The program's normal termination occurs when q or Q is typed. For information about compiling and linking Bounce.c, see Compiling and Linking Multithread Programs.
Example
Code
// sample_multithread_c_program.c// compile with: /c//// Bounce - Creates a new thread each time the letter 'a' is typed.// Each thread bounces a happy face of a different color around// the screen. All threads are terminated when the letter 'Q' is// entered.//#include<windows.h>#include<stdlib.h>#include<string.h>#include<stdio.h>#include<conio.h>#include<process.h>#defineMAX_THREADS 32
// The function getrandom returns a random number between// min and max, which must be in integer range.#definegetrandom( min, max ) (SHORT)((rand() % (int)(((max) + 1) - \
(min))) + (min))
intmain( void ); // Thread 1: mainvoidKbdFunc( void ); // Keyboard input, thread dispatchvoidBounceProc( void*MyID ); // Threads 2 to n: displayvoidClearScreen( void ); // Screen clearvoidShutDown( void ); // Program shutdownvoidWriteTitle( intThreadNum ); // Display title bar informationHANDLEhConsoleOut; // Handle to the consoleHANDLEhRunMutex; // "Keep Running" mutexHANDLEhScreenMutex; // "Screen update" mutexintThreadNr; // Number of threads startedCONSOLE_SCREEN_BUFFER_INFOcsbiInfo; // Console informationintmain() // Thread One
{
// Get display screen information & clear the screen.hConsoleOut=GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( hConsoleOut, &csbiInfo );
ClearScreen();
WriteTitle( 0 );
// Create the mutexes and reset thread count.hScreenMutex=CreateMutex( NULL, FALSE, NULL ); // ClearedhRunMutex=CreateMutex( NULL, TRUE, NULL ); // SetThreadNr=0;
// Start waiting for keyboard input to dispatch threads or exit.KbdFunc();
// All threads done. Clean up handles.CloseHandle( hScreenMutex );
CloseHandle( hRunMutex );
CloseHandle( hConsoleOut );
}
voidShutDown( void ) // Shut down threads
{
while ( ThreadNr>0 )
{
// Tell thread to die and record its death.ReleaseMutex( hRunMutex );
ThreadNr--;
}
// Clean up display when doneWaitForSingleObject( hScreenMutex, INFINITE );
ClearScreen();
}
voidKbdFunc( void ) // Dispatch and count threads.
{
intKeyInfo;
do
{
KeyInfo=_getch();
if ( tolower( KeyInfo ) =='a'&&ThreadNr<MAX_THREADS )
{
ThreadNr++;
_beginthread( BounceProc, 0, &ThreadNr );
WriteTitle( ThreadNr );
}
} while( tolower( KeyInfo ) !='q' );
ShutDown();
}
voidBounceProc( void*pMyID )
{
charMyCell, OldCell;
WORDMyAttrib, OldAttrib;
charBlankCell=0x20;
COORDCoords, Delta;
COORDOld= {0,0};
DWORDDummy;
char*MyID= (char*)pMyID;
// Generate update increments and initial// display coordinates.srand( (unsigned int) *MyID*3 );
Coords.X=getrandom( 0, csbiInfo.dwSize.X-1 );
Coords.Y=getrandom( 0, csbiInfo.dwSize.Y-1 );
Delta.X=getrandom( -3, 3 );
Delta.Y=getrandom( -3, 3 );
// Set up "happy face" & generate color// attribute from thread number.if( *MyID>16)
MyCell=0x01; // outline faceelseMyCell=0x02; // solid faceMyAttrib=*MyID&0x0F; // force black backgrounddo
{
// Wait for display to be available, then lock it.WaitForSingleObject( hScreenMutex, INFINITE );
// If we still occupy the old screen position, blank it out.ReadConsoleOutputCharacter( hConsoleOut, &OldCell, 1,
Old, &Dummy );
ReadConsoleOutputAttribute( hConsoleOut, &OldAttrib, 1,
Old, &Dummy );
if (( OldCell==MyCell ) && (OldAttrib==MyAttrib))
WriteConsoleOutputCharacter( hConsoleOut, &BlankCell, 1,
Old, &Dummy );
// Draw new face, then clear screen lockWriteConsoleOutputCharacter( hConsoleOut, &MyCell, 1,
Coords, &Dummy );
WriteConsoleOutputAttribute( hConsoleOut, &MyAttrib, 1,
Coords, &Dummy );
ReleaseMutex( hScreenMutex );
// Increment the coordinates for next placement of the block.Old.X=Coords.X;
Old.Y=Coords.Y;
Coords.X+=Delta.X;
Coords.Y+=Delta.Y;
// If we are about to go off the screen, reverse directionif( Coords.X<0||Coords.X >= csbiInfo.dwSize.X )
{
Delta.X=-Delta.X;
Beep( 400, 50 );
}
if( Coords.Y<0||Coords.Y>csbiInfo.dwSize.Y )
{
Delta.Y=-Delta.Y;
Beep( 600, 50 );
}
}
// Repeat while RunMutex is still taken.while ( WaitForSingleObject( hRunMutex, 75L ) ==WAIT_TIMEOUT );
}
voidWriteTitle( intThreadNum )
{
enum {
sizeOfNThreadMsg=80
};
charNThreadMsg[sizeOfNThreadMsg];
sprintf_s( NThreadMsg, sizeOfNThreadMsg,
"Threads running: %02d. Press 'A' ""to start a thread,'Q' to quit.", ThreadNum );
SetConsoleTitle( NThreadMsg );
}
voidClearScreen( void )
{
DWORDdummy;
COORDHome= { 0, 0 };
FillConsoleOutputCharacter( hConsoleOut, ' ',
csbiInfo.dwSize.X*csbiInfo.dwSize.Y,
Home, &dummy );
}