J
James Niceguy
Hi,
I have written a simple program that does the following:
The main program will spown MAX_THREADS number of threads, each
of which will simply add to a global shared counter for MAX_COUNT
times and notify the main thread it has finished by clearing a
mutex before exiting. The main thread will simply check verify the
final result in the global shared counter, wait for each worker
thread has notify finishing, and exit.
The complete C program is at the end of this message. Anyway,
the problem is not in the logic of this program. It is really an
anomaly I encountered while testing it with different values of
MAX_THREADS.
I found that for some reason, if the MAX_THREADS value is 1 or 2 the
hRunMutex[0] will be corrupted during execution for no apparent
reason. The program will go into an infinite loop in CheckCounter()
function. I can detect this by checking if the return value of
WaitForSingleObject() function equals WAIT_FAILED, etc, but that's
another topic. So I was playing with the program and tried to
print out the value of hRunMutex[0] at various points and I found
that if I add on extra global variable definition, the whole problem
goes away! That is if I add "char func[10];".
For MAX_THREADS value 3 and above, the program works well with
or without that line. But for value 1 and 2, it has to have that line.
Otherwise it gets a currupt handle during execution and could not
finish.
I am really curious about the cause of this problem. I'd appreciate
if anyone can shed some light on it for me, because besides blaming
Microsoft, I am completely clueless.
And the reason I am blaming Microsoft is I am using Visual Studio
..NET to compile the program. Just create a project with Managed C++
Empty Project, and add this file to project to compile and run it.
Thanks!
Regards,
James
/* counters.c file.*/
/* This program will create MAX_THREADS number of threads. Each of
them
* will increment a shared counter for MAX_COUNT times, sleeping for a
* random number of milliseconds in between each increment. The main
* thread will wait until the shared counter reaches
MAX_THREADS*MAX_COUNT.
* It will then wait for enter key from input before exiting to allow
* examining the output.
*/
#include <windows.h>
#include <stdio.h>
#include <process.h>
#define MAX_THREADS 2
#define MAX_COUNT 3
/* getrandom returns a random number between min and max. */
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) +
(min))
int main( void ); /* Thread 1: main */
void CountProc( int * MyID ); /* Threads 2 to MAX_THREADS:
Increment the shared counter */
void CheckCounter( void ); /* Function CheckCounter called
by main() */
void WriteMsg( int iThreadNum, int iMyCount, int iTotalCount ); /*
Display information */
HANDLE hRunMutex[MAX_THREADS]; /* Notification mutex */
int iThreadNum; /* Number of threads started */
HANDLE hCounterMutex; /* Shared counter mutex */
int iSharedCounter; /* Shared counter used by all threads
*/
int ThreadID[MAX_THREADS]; /* Thread ID for diaplay */
int done[MAX_THREADS] = {0}; /* Array for thread status */
char func[10]; // Necessary to make it work for MAX_THREADS = 1
and 2 cases. Microsoft bug?!
int main() /* Thread One */
{
/* Create the mutexes and reset thread count. */
int i;
iSharedCounter = 0;
for(i=0;i< MAX_THREADS;i++)
{
hRunMutex = CreateMutex( NULL, TRUE, NULL ); /* Set */
}
hCounterMutex = CreateMutex( NULL, FALSE, NULL ); /* Cleared */
iThreadNum = 0;
WriteMsg( 0, 0, iSharedCounter );
/* Create the counting threads. */
while( iThreadNum < MAX_THREADS )
{
iThreadNum++;
ThreadID[iThreadNum] = iThreadNum;
_beginthread( CountProc, 0, &ThreadID[iThreadNum] );
}
/* Wait until the shared counter reaches the limit. */
CheckCounter();
WriteMsg( 0, 0, iSharedCounter );
/* All threads done. Clean up handles. */
for(i=0;i<MAX_THREADS;i++)
{
/* if(done != 1) */
CloseHandle( hRunMutex );
}
CloseHandle( hCounterMutex);
/* Pause for 10 seconds before exiting */
printf("Press enter to exit...");
getchar();
}
void CheckCounter( void ) /* Check shared counter */
{
int i;
/* Check the share counter limit, sleep in between each check */
while ( iSharedCounter < MAX_COUNT * MAX_THREADS)
{
Sleep(getrandom(0,100));
}
/* Wait for the woker threads to exit first */
while ( iThreadNum > 0 )
{
for(i = 0;i<MAX_THREADS;i++)
{
if(done == 0 )
{
int ret = WaitForSingleObject( hRunMutex, 100 );
if(ret == WAIT_OBJECT_0 /*|| ret == WAIT_FAILED*/)
{
iThreadNum--;
done=ret+2;
}
}
}
Sleep(getrandom(0,100));
}
}
void CountProc( int *MyID )
{
int i=0;
do
{
/* Wait for counter to be available, then lock it. */
WaitForSingleObject( hCounterMutex, INFINITE );
iSharedCounter++;
WriteMsg(*MyID, i, iSharedCounter);
ReleaseMutex( hCounterMutex );
i++;
Sleep(getrandom(0, 5));
}
while(i < MAX_COUNT);
ReleaseMutex( hRunMutex[(*MyID)-1] );
}
void WriteMsg( int iThreadNum, int iMyCount, int iTotalCount )
{
printf("Thread ID: %d, Local Count: %d, Shared Count: %d \n",
iThreadNum, iMyCount, iTotalCount );
}
I have written a simple program that does the following:
The main program will spown MAX_THREADS number of threads, each
of which will simply add to a global shared counter for MAX_COUNT
times and notify the main thread it has finished by clearing a
mutex before exiting. The main thread will simply check verify the
final result in the global shared counter, wait for each worker
thread has notify finishing, and exit.
The complete C program is at the end of this message. Anyway,
the problem is not in the logic of this program. It is really an
anomaly I encountered while testing it with different values of
MAX_THREADS.
I found that for some reason, if the MAX_THREADS value is 1 or 2 the
hRunMutex[0] will be corrupted during execution for no apparent
reason. The program will go into an infinite loop in CheckCounter()
function. I can detect this by checking if the return value of
WaitForSingleObject() function equals WAIT_FAILED, etc, but that's
another topic. So I was playing with the program and tried to
print out the value of hRunMutex[0] at various points and I found
that if I add on extra global variable definition, the whole problem
goes away! That is if I add "char func[10];".
For MAX_THREADS value 3 and above, the program works well with
or without that line. But for value 1 and 2, it has to have that line.
Otherwise it gets a currupt handle during execution and could not
finish.
I am really curious about the cause of this problem. I'd appreciate
if anyone can shed some light on it for me, because besides blaming
Microsoft, I am completely clueless.
And the reason I am blaming Microsoft is I am using Visual Studio
..NET to compile the program. Just create a project with Managed C++
Empty Project, and add this file to project to compile and run it.
Thanks!
Regards,
James
/* counters.c file.*/
/* This program will create MAX_THREADS number of threads. Each of
them
* will increment a shared counter for MAX_COUNT times, sleeping for a
* random number of milliseconds in between each increment. The main
* thread will wait until the shared counter reaches
MAX_THREADS*MAX_COUNT.
* It will then wait for enter key from input before exiting to allow
* examining the output.
*/
#include <windows.h>
#include <stdio.h>
#include <process.h>
#define MAX_THREADS 2
#define MAX_COUNT 3
/* getrandom returns a random number between min and max. */
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) +
(min))
int main( void ); /* Thread 1: main */
void CountProc( int * MyID ); /* Threads 2 to MAX_THREADS:
Increment the shared counter */
void CheckCounter( void ); /* Function CheckCounter called
by main() */
void WriteMsg( int iThreadNum, int iMyCount, int iTotalCount ); /*
Display information */
HANDLE hRunMutex[MAX_THREADS]; /* Notification mutex */
int iThreadNum; /* Number of threads started */
HANDLE hCounterMutex; /* Shared counter mutex */
int iSharedCounter; /* Shared counter used by all threads
*/
int ThreadID[MAX_THREADS]; /* Thread ID for diaplay */
int done[MAX_THREADS] = {0}; /* Array for thread status */
char func[10]; // Necessary to make it work for MAX_THREADS = 1
and 2 cases. Microsoft bug?!
int main() /* Thread One */
{
/* Create the mutexes and reset thread count. */
int i;
iSharedCounter = 0;
for(i=0;i< MAX_THREADS;i++)
{
hRunMutex = CreateMutex( NULL, TRUE, NULL ); /* Set */
}
hCounterMutex = CreateMutex( NULL, FALSE, NULL ); /* Cleared */
iThreadNum = 0;
WriteMsg( 0, 0, iSharedCounter );
/* Create the counting threads. */
while( iThreadNum < MAX_THREADS )
{
iThreadNum++;
ThreadID[iThreadNum] = iThreadNum;
_beginthread( CountProc, 0, &ThreadID[iThreadNum] );
}
/* Wait until the shared counter reaches the limit. */
CheckCounter();
WriteMsg( 0, 0, iSharedCounter );
/* All threads done. Clean up handles. */
for(i=0;i<MAX_THREADS;i++)
{
/* if(done != 1) */
CloseHandle( hRunMutex );
}
CloseHandle( hCounterMutex);
/* Pause for 10 seconds before exiting */
printf("Press enter to exit...");
getchar();
}
void CheckCounter( void ) /* Check shared counter */
{
int i;
/* Check the share counter limit, sleep in between each check */
while ( iSharedCounter < MAX_COUNT * MAX_THREADS)
{
Sleep(getrandom(0,100));
}
/* Wait for the woker threads to exit first */
while ( iThreadNum > 0 )
{
for(i = 0;i<MAX_THREADS;i++)
{
if(done == 0 )
{
int ret = WaitForSingleObject( hRunMutex, 100 );
if(ret == WAIT_OBJECT_0 /*|| ret == WAIT_FAILED*/)
{
iThreadNum--;
done=ret+2;
}
}
}
Sleep(getrandom(0,100));
}
}
void CountProc( int *MyID )
{
int i=0;
do
{
/* Wait for counter to be available, then lock it. */
WaitForSingleObject( hCounterMutex, INFINITE );
iSharedCounter++;
WriteMsg(*MyID, i, iSharedCounter);
ReleaseMutex( hCounterMutex );
i++;
Sleep(getrandom(0, 5));
}
while(i < MAX_COUNT);
ReleaseMutex( hRunMutex[(*MyID)-1] );
}
void WriteMsg( int iThreadNum, int iMyCount, int iTotalCount )
{
printf("Thread ID: %d, Local Count: %d, Shared Count: %d \n",
iThreadNum, iMyCount, iTotalCount );
}