Reputation: 870
I'm trying to learn multithreading and I thought that parallelizing algorithms would be a good exercise. Quicksort and Merge sort in particular.
My problem is that arguments become corrupt from calling pthread_create
to the point of entering the function associated with the call.
My Quicksort function looks like this
static void* quick_sort( void* threadData )
{
struct ThreadData* data = (struct ThreadData*)threadData;
unsigned pivot_index;
pthread_mutex_lock( &lock );
printf( "\nThread %d : Entering quick_sort with low = %d, high = %d ", data->threadID, data->low, data->high );
pthread_mutex_unlock( &lock );
// No need to sort a vector of zero or one element
if ( data->low >= data->high )
return NULL;
// Select the pivot value
pivot_index = ( data->low + data->high ) / 2;
// Partition the vector
pivot_index = partition( data->collection, data->low, data->high, pivot_index );
/* Set thread data */
//-------------------------------------------------
struct ThreadData left, right;
left.collection = data->collection;
left.low = data->low;
left.high = pivot_index - 1;
left.threadID = data->threadID;
right.collection = data->collection;
right.low = pivot_index + 1;
right.high = data->high;
right.threadID = data->threadID;
//------------------------------------------------
/* sort the two sub arrays */
if ( data->low < pivot_index )
{
pthread_mutex_lock( &lock ); // Lock mutex
if( numRunningThreads < NUM_THREADS ) // Check for an available thread
{
// Find available thread index
int j;
for( j = 0; j < NUM_THREADS; j++ )
{
if( !runningThreads[j] )
{
left.threadID = j; // threadPool[j] is available
runningThreads[j] = true; // Set thread as running
break;
}
}
/* Use mutex lock when incrementing numRunningThreads
since it is a global variable and shared by all threads */
numRunningThreads++;
printf( "\n Dispatching thread %d -- ", j );
printf( "low = %d, high = %d, pivot_index = %d, threadID = %d ---", left.low, left.high, pivot_index, left.threadID );
printf( " %d threads running", numRunningThreads );
pthread_mutex_unlock( &lock );
// Create new thread
pthread_create( &threadPool[left.threadID], NULL, &quick_sort, (void*)&left );
}
else
{
// There are NO available threads
pthread_mutex_unlock( &lock );
quick_sort( (void*)&left ); // Use existing thread
}
}
if ( pivot_index < data->high )
quick_sort( (void*)&right );
return NULL;
}
Edit
The usage of ´pthread_create´ is
pthread_create( &threadPool[left.threadID], NULL, &quick_sort, (void*)&left );
The function is initially called from main
:
// Use first thread in threadPool
runningThreads[0] = true;
numRunningThreads++;
pthread_create( &threadPool[0], NULL, &quick_sort, (void*)&threadData );
// Join threads
for( i = 0; i < NUM_THREADS; i++ )
{
if( runningThreads[i] )
{
pthread_join( threadPool[i], NULL );
pthread_mutex_lock( &lock );
printf( "\nJoining thread %d", i );
runningThreads[i] = false;
numRunningThreads--;
pthread_mutex_unlock( &lock );
}
}
According to the output the data is corrupt when entering the function
Thread 3 : Entering quick_sort with low = -259450448, high = 32567
Any thoughts on what I'm doing wrong?
Upvotes: 0
Views: 719
Reputation: 25752
In the thread a automatic variable left
is defined and initialized:
struct ThreadData left, right;
then under certain conditions that variable is passed to a newly created thread. This is not done under any kind of locking mechanism:
pthread_create( &threadPool[left.threadID], NULL, &quick_sort, (void*)&left );
Immediately after creating that thread and passing left
to it, the current thread can immediately exit, while at the same time the created thread still runs and uses the variable left
:
if ( pivot_index < data->high )
quick_sort( (void*)&right );
return NULL;
then the variable left
stops existing, while still being used, causing undefined behavior.
Solution is to use allocated variables, i.e. use malloc, pass those variables to the created threads and free them when they are no longer used.
Upvotes: 3