Free Counter
These examples are based on the stanford CS107 lecture 15 - lecture 20.
youtube playlist
Since C++ multi-threading library is operation system dependent, the codes listed here are tested on Visual C++ 2008 Express Edition.
Windows Multithreading Helloworld
Several Agents are selling some amount of tickets in parallel, their access to the global parameter numTicketsp are synchronized by a Mutex.
-------------------------------
The following code is tested on Visual C++ 2008 Express Edition.
Show Code   Hide Code
--------------------------------
#include <iostream>
#include <string>
#include <fstream>
#include <stdio.h>
#include <windows.h>
#include <process.h> // needed for _beginthread()
#include <cstdlib>
#define NUMTICKETS 150
#define NUMAGENTS 10
using namespace std;
static HANDLE hThrd; // thread handle
static HANDLE hMutex = 0; // handle of mutex
typedef struct ST{
int agentid;
int * numTicketsp;
}thestruct;
class TimeOutExc {
// Add functionality if needed by your application.
};
void SellTickets(thestruct* s)
{
int agent = s->agentid +1;
while(true){
if(WaitForSingleObject(hMutex, 100000)==WAIT_TIMEOUT)
throw TimeOutExc();
if(*(s->numTicketsp) == 0) break;
cout << "Agent " << agent << " sells the " << NUMTICKETS - *(s->numTicketsp) +1 <<"th ticket, \n" << endl;
(*(s->numTicketsp)) --;
ReleaseMutex(hMutex);
int random_integer = rand();
if(random_integer <= RAND_MAX/2)
Sleep(1000); //just simulate the time spent on business logic
}
printf("Agent %d: All done. \n", agent);
ReleaseMutex(hMutex);
}
int main()
{
string s;
int numAgents = NUMAGENTS;
int numTickets = NUMTICKETS;
hMutex = CreateMutex(NULL, 0, NULL);
for(int i=0; i<numAgents; i++){
thestruct st;
st.agentid = i;
st.numTicketsp = &numTickets;
hThrd = (HANDLE)_beginthread( (void(*)(void*))SellTickets, 0, (void*)&st );
Sleep(200);
//the main thread must sleep for a while in order to give thread some time to create their stack,
//otherwise, the local variable i will have no place to push to, as a result, once the stack is ready, the local variable i could have changed to numAgents already,
//you then wonder why all threads get the same agent number.
}
getline(cin,s);
return 0;
}
Simple Semaphor Example
A simple network server :
writer() grab data from network connection, then write characters to buffer, at the mean-time reader() constantly read character from the same buffer.
Two semaphors "emptyBuffer" and "fullBuffer" are used here to make sure reader() and writer() won't step onto each other.
-------------------------------
The following code is tested on Visual C++ 2008 Express Edition.
Show Code   Hide Code
--------------------------------
#include <iostream>
#include <string>
#include <stdio.h>
#include <windows.h>
#include <cstdlib>
using namespace std;
#define MAX_SEM_COUNT 8
#define THREADCOUNT 2
HANDLE emptyBuffer;
HANDLE fullBuffer;
DWORD WINAPI ThreadProc_reader( LPVOID );
DWORD WINAPI ThreadProc_writer( LPVOID );
char buffer[8];
//network server
void main()
{
string s;
HANDLE aThread[THREADCOUNT];
HANDLE Thread_reader;
DWORD ThreadID_reader;
HANDLE Thread_writer;
DWORD ThreadID_writer;
emptyBuffer = CreateSemaphore(
NULL, // default security attributes
MAX_SEM_COUNT, // initial count
MAX_SEM_COUNT, // maximum count
NULL); // unnamed semaphore
if (emptyBuffer == NULL)
{
printf("CreateSemaphore emptyBuffer error: %d\n", GetLastError());
return;
}
fullBuffer = CreateSemaphore(
NULL, // default security attributes
0, // initial count
MAX_SEM_COUNT, // maximum count
NULL); // unnamed semaphore
if (fullBuffer == NULL)
{
printf("CreateSemaphore fullBuffer error: %d\n", GetLastError());
return;
}
Thread_reader = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc_reader,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID_reader); // receive thread identifier
if( Thread_reader == NULL )
{
printf("CreateThread reader error: %d\n", GetLastError());
return;
}
Thread_writer = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) ThreadProc_writer,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID_writer); // receive thread identifier
if( Thread_writer == NULL )
{
printf("CreateThread writer error: %d\n", GetLastError());
return;
}
// Wait for all threads to terminate
aThread[0] = Thread_writer;
aThread[1] = Thread_reader;
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
CloseHandle(Thread_reader);
CloseHandle(Thread_writer);
CloseHandle(emptyBuffer);
CloseHandle(fullBuffer);
getline(cin,s);
}
DWORD WINAPI ThreadProc_writer( LPVOID lpParam )
{
DWORD dwWaitResult;
int random_integer;
for(int i=0; i<40; i++){
char c = 'A' + i;
dwWaitResult = WaitForSingleObject(
emptyBuffer, // handle to semaphore
100000); // time-out interval
switch (dwWaitResult)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
// printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
// Perform task
buffer[i%8]=c;
// Simulate thread spending time on task
random_integer = rand();
if(random_integer <= RAND_MAX/2){
cout << "waiting for network..." <<endl;
Sleep(1000);
}
// Release the semaphore when task is finished
if (!ReleaseSemaphore(
fullBuffer, // handle to semaphore
1, // increase count by one
NULL) ) // not interested in previous count
{
printf("ReleaseSemaphore error: %d\n", GetLastError());
}
// cout << "write "<<i+1<<"th character to buffer: " << buffer[i%8] << endl;
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
printf("Thread %d: wait timed out\n", GetCurrentThreadId());
break;
}
}
return TRUE;
}
DWORD WINAPI ThreadProc_reader( LPVOID lpParam )
{
DWORD dwWaitResult;
char c;
for(int i=0; i<40; i++){
dwWaitResult = WaitForSingleObject(
fullBuffer, // handle to semaphore
100000); // time-out interval
switch (dwWaitResult)
{
// The semaphore object was signaled.
case WAIT_OBJECT_0:
// printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
// Perform task
c = buffer[i%8];
// Simulate thread spending time on task
Sleep(5);
// Release the semaphore when task is finished
if (!ReleaseSemaphore(
emptyBuffer, // handle to semaphore
1, // increase count by one
NULL) ) // not interested in previous count
{
printf("ReleaseSemaphore error: %d\n", GetLastError());
}
//process data
cout << "read "<<i+1<<"th character from buffer: " << c << endl;
break;
// The semaphore was nonsignaled, so a time-out occurred.
case WAIT_TIMEOUT:
printf("Thread %d: wait timed out\n", GetCurrentThreadId());
break;
}
}
return TRUE;
}
A little bit advanced Semaphor Example
Classic Five philosophers problem:
There are 5 philosophers who sit around a table. There is a folk between each neighboring philosopher. Each philosopher must grab two folks to be able to eat. Once a philosopher finished eating, he will put the forks back and waiting for the next chance to eat. The objective is to write a multi-threading program to simulate the situation.
The trick is -- suppose each philosopher is holding a folk at his/her left hand, and waiting for the philosopher at his right hand side to give up a fork. The philosopher at the right hand will not gonna to give up his fork, because he/she is also waiting for a fork from the right side...A dead-lock condition is thus created, nobody will be able to eat and they will be waiting forever.
To resolve the dead-lock, we only allow at most 4 philosophers to grab forks at any given moment, the rest philosophers have to wait.
The pseudocode is as follows:
Semaphore forks[]={1,1,1,1,1};
Semaphore numAllowedToEat(4);
void philosophor(int id)
{
for(int i=0; i<3; i++){
think();
SW(umAllowedToEat);
SW(forks[id]);
SW(forks[(id+1)%5]);
eat();
SS(forks[id]);
SS(forks[(id+1)%5]);
SS(numAllowedToEat);
}
-------------------------------
The following code is tested on Visual C++ 2008 Express Edition.
Show Code   Hide Code
--------------------------------
#include <iostream>
#include <string>
#include <stdio.h>
#include <windows.h>
#include <cstdlib>
#include <ctime>
using namespace std;
#define THREADCOUNT 5
DWORD WINAPI philosopher( LPVOID );
HANDLE forks[THREADCOUNT];
HANDLE numAllowedToEat;
class TimeOutExc {
// Add functionality if needed by your application.
};
void main()
{
string s;
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
for( i=0; i < THREADCOUNT; i++ ){
forks[i] = CreateSemaphore(
NULL, // default security attributes
1, // initial count
2, // maximum count
NULL); // unnamed semaphore
if (forks[i] == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return;
}
Sleep(100);
//the main thread need to sleep for a while in order to give thread some time to initialize
}
numAllowedToEat = CreateSemaphore(
NULL, // default security attributes
4, // initial count
4, // maximum count
NULL); // unnamed semaphore
if (numAllowedToEat == NULL)
{
printf("CreateSemaphore numAllowedToEat error: %d\n", GetLastError());
return;
}
// Create worker threads
for( i=0; i < THREADCOUNT; i++ ){
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE) philosopher,
&i, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if( aThread[i] == NULL ) {
printf("CreateThread error: %d\n", GetLastError());
return;
}
Sleep(100);
//the main thread need to sleep for a while in order to give thread some time to initialize
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
for( i=0; i < THREADCOUNT; i++ ){
CloseHandle(aThread[i]);
CloseHandle(forks[i]);
}
CloseHandle(numAllowedToEat);
getline(cin,s);
}
DWORD WINAPI philosopher( LPVOID lpParam )
{
int id = *((int*)lpParam);
int random_integer;
for(int i=0; i<100; i++){
// Simulate thread spending time on task
random_integer = rand();
if(random_integer <= RAND_MAX/2)
Sleep(1000);
if(WaitForSingleObject(numAllowedToEat, 100000)==WAIT_TIMEOUT)
throw TimeOutExc();
if(WaitForSingleObject(forks[id], 100000)==WAIT_TIMEOUT)
throw TimeOutExc();
if(WaitForSingleObject(forks[(id+1)%5], 100000)==WAIT_TIMEOUT)
throw TimeOutExc();
printf("NO: %d philosopher is eating...\n", id);
if (!ReleaseSemaphore(forks[id],1, NULL) )
printf("ReleaseSemaphore error forks[id]: %d\n", GetLastError());
if (!ReleaseSemaphore(forks[(id+1)%5],1, NULL) )
printf("ReleaseSemaphore error forks[(id+1)%5]: %d\n", GetLastError());
if (!ReleaseSemaphore(numAllowedToEat,1, NULL) )
printf("ReleaseSemaphore error (numAllowedToEat): %d\n", GetLastError());
}
return TRUE;
}
No comments:
Post a Comment