[ Home | Syllabus |Course Notes]
Why Threads?
Thread runs a special function with one parameter.
WIN32 supports a general WaitFor mechanism which works for many different kinds of events.
(Source Code is here)
// ... #include <windows.h> // for defining HANDLE, Sleep const int SLEEP_TIME = 1000; int global1; // file global void testThread(int* myId ); // thread prototype void main() { HANDLE testHandle; DWORD threadId; int id = 1; global1 = 33; testHandle = CreateThread (0, // no child process cannot inherit 0, // gives same stack space as parent thread (LPTHREAD_START_ROUTINE) TestThread, &id, // Pass in one parameter 0, // Put into ready Q &threadID); // system wide thread ID Sleep (SLEEP_TIME); // sleep for one second - give thread a chance global1 = 55; WaitForSingleObject(testHandle, INFINITE); } void testThread(int* myId) { cout << "Started Thread ID: " << *myId << endl; cout << "BEFORE: Global1 is: " << global1 << endl; Sleep(2*SLEEP_TIME); // give main thread chance to change global1 cout << "AFTER: Global1 is: " << global1 << endl; }
What will the output?
void testThread(DWORD myId);
void main() { HANDLE testHandles[2];
testHandles[0] = CreateThread(0,0, (LPTHREAD_START_ROUTINE) testThread, (void*)id, 0, &threadId); id++; testHandles[1] = CreateThread(0,0, (LPTHREAD_START_ROUTINE) testThread, (void*)id, 0, &threadId); Sleep(SLEEP_TIME); // sleep for one second WaitForMultipleObjects(2, testHandles, TRUE /* wait for all */, INFINITE); }
// Separate file //**** all threads started with this code will share the file global variable "global2" int global2 = 12345; void testThread(DWORD myId) { int id = myId; cout << "Started Thread ID: " << id << endl; cout << "BEFORE: Global2 is: " << global2 << endl; global2 = id; Sleep(id*SLEEP_TIME); // give main thread chance to change global1 cout << "AFTER: Global2 is: " << global2 << endl; }
// What will be the output?
(Source Code is here)
DWORD tlsIndex;
void testThread(int* myId);
void main() { // . . . tlsIndex = TlsAlloc(); testHandles[0] = CreateThread(0,0, (LPTHREAD_START_ROUTINE) testThread, &id, 0, &threadId); Sleep(SLEEP_TIME); // give first thread a chance to save its parameter //. . . separate file for thread code
extern DWORD tlsIndex; void checkGlobal(int); void testThread(int* myId) { int id = *myId; int global3 = id; TlsSetValue(tlsIndex, &global3); checkGlobal(id); } void checkGlobal(int id) { int* tls; tls = (int*) TlsGetValue(tlsIndex); cout << "BEFORE: Global3 is: " << *tls << endl; *tls = id*1000; Sleep(id*SLEEP_TIME); // give main thread chance to change global1 cout << "AFTER: Global3 is: " << *tls << endl; }
// What output?
// Prototype to thread call VOID talkToClient(VOID * cs); int main() { // . . .
DWORD threadID; HANDLE clientThread; serverSocket = getServerSocket(); while (true) { // accept a connection from a client clientSocket=accept(serverSocket, (LPSOCKADDR) &clientSockAddr, &addrLen); //. . .
clientThread = CreateThread (0, // no child process cannot inherit 0, // gives same stack space as parent thread (LPTHREAD_START_ROUTINE) talkToClient, (VOID *) clientSocket, // Pass in one parameter 0, // Put into ready Q &threadID); // system wide thread ID // . . .
} } VOID talkToClient(VOID *cs) { SOCKET socket2client=(SOCKET)cs; NET_CONTROL request; while(TRUE) // loop until killed { request = getControl(socket2client); if (request == FAILURE) { shutdown(socket2client, 2); // 2 shutdown send and receive closesocket(socket2client); ExitThread(0); } switch (request) // . . .
VARIABLE:
FUNCTIONS:
#include <windows.h> //. . . volatile INT count; CRITICAL_SECTION critSec; void CountThread(INT iterations) { //. . . for (i=0; i<iterations; i++) { EnterCriticalSection(&critSec); x=count; x++; count=x; LeaveCriticalSection(&critSec); } } void main(void) { // . . . InitializeCriticalSection(&critSec); for (i=0; i<numThreads; i++) { // create a thread and pass it the pointer // to its "params" struct handles[i]=CreateThread(0, 0, (LPTHREAD_START_ROUTINE) CountThread, (VOID *) 25000, 0, &threadID); } WaitForMultipleObjects(numThreads, handles, TRUE, INFINITE); DeleteCriticalSection(&critSec); }
Can be used across processes by naming it.
VARIABLE:
FUNCTIONS:
void CountThread(INT iterations) { INT i; INT x; HANDLE mutex; mutex = CreateMutex(0, FALSE, "counterMutex"); // only first thread actually creates it for (i=0; i<iterations; i++) { WaitForSingleObject(mutex, INFINITE); x=count; x++; count=x; ReleaseMutex(mutex); } CloseHandle(mutex); }
The bounded buffer example is kind of neat. p. 231--
In automatic mode, like a MUTEX, in manual can be used to release a number of waiting processes/threads.
Used to wait for many things (p. 257)
Also allows a time out value.
Multiple Objects can be waited for