Tutorial on Threads

By Yamini (course TA)

In a multi-threaded program different threads run concurrently. The executing process starts a main thread which can then invoke other threads. There may be no difference between main thread and other threads afterwards.

Threads are like lightweight processes which share the resources of the process in which they exist. This is the major advantage of multi threading but it would require careful synchronization etc, otherwise it may result in the state of the resources being changed wrongly.

pthread Library Routines
Some of the important routines are listed below:

Synchronization between threads
Following are the facilities provided by pthread library:

There are other routines provided by pthread library to manipulate the thread attributes. These attributes can be changed to change and access the stack size get the address of the stack. Also to provide different scheduling and priority setting policies.

Example Programs
/* Program to compute the product of two matrices MA and MB.
The result is stored in matrix MC;
Threads are created to compute each element of MC */


#include
#define ARRAY_SIZE 10

typedef int * matrix_t;
void peer_mult();
void mult();


typedef struct {
int id;
int size;
int row;
int col;
matrix_t *MA, *MB, *MC;
} matrix_work_order_t;

main()
{
int i, size = ARRAY_SIZE, row, col, id;
matrix_t MA, MB, MC;

matrix_work_order_t *work_orderp;
pthread_t peer[ARRAY_SIZE * ARRAY_SIZE];

printf(" Enter the Matrix size and the two matrices ");

scanf("%d", &size);

MA = (int *) malloc( size * size * sizeof( int));
MB = (int *) malloc( size * size * sizeof( int));
MC = (int *) malloc( size * size * sizeof( int));

for( row = 0; row < size; row++)
for( col = 0; col < size; col++)
scanf("%d", (MA + row * size + col));

for( row = 0; row < size; row++)
for( col = 0; col < size; col++)
scanf("%d", (MB + row * size + col));

for( row = 0; row < size; row++)
{
for( col = 0; col < size; col++)
printf("%d \t", *(MA + row * size + col));

printf("");
}
for( row = 0; row < size; row++)
{
for( col = 0; col < size; col++)
printf("%d \t", *(MB + row * size + col));

printf("");
}

for( row = 0; row < size; row++)
{
for( col = 0; col < size; col++)
{
id = col + row* size;
work_orderp = (matrix_work_order_t *) malloc( sizeof(matrix_work_order_t));
work_orderp->id = id;
work_orderp->size = size;
work_orderp->row = row;
work_orderp->col = col;
work_orderp->MA = &MA;
work_orderp->MB = &MB;
work_orderp->MC = &MC;

/****** Create a thread to compute MC[row][col] *************/

pthread_create(&(peer[id]), NULL, (void *)peer_mult,
(void *)work_orderp);
}
}

/********* Wait for all threads to finish *************/

for(i = 0; i < (size * size); i++)
{
pthread_join( peer[i], NULL);
}


printf(" The result matrix ");
for( row = 0; row < size; row++)
{
for( col = 0; col < size; col++)
printf("%d \t", *(MC + row * size + col));

printf("");
}
}

void peer_mult(matrix_work_order_t *work_orderp)
{
mult( work_orderp->size, work_orderp->row, work_orderp->col,
*( work_orderp->MA), *( work_orderp->MB), *( work_orderp->MC));
free(work_orderp);
}


void mult(int size, int row, int col, matrix_t MA, matrix_t MB, matrix_t MC )
{
int pos;
*(MC + size * row + col) = 0;
for( pos = 0; pos < size; pos++)
{
*(MC+ size *row+ col) = *(MC + size * row + col) + ( (*(MA
+ size * row + pos)) * (*(MB + size * pos + col)) );
}
}

/*********************************************************/

/*** Program with a shared linked list which can be used by more than one
threads by using mutex variables for synchronization *****/

#include

typedef struct list_node {
int index;
int datap;
struct list_node *nextp;
} list_node_t;

typedef struct llist {
list_node_t *first;
pthread_mutex_t mutex; /**** Mutex variable associated with llist ***/
} list_t;

typedef struct {
int index;
int datap;
list_t **listp;
} work_order_t; /***** Argument to be passed with create_thread ******/


int list_init(list_t *listp);
void list_insert_data();
void list_insert();
void list_show( list_t *listp);

main( )
{
int j, i = 1, size = 10;
pthread_t peer[10];
list_t *my_list;
work_order_t *work_orderp;

list_init( my_list);

for( j = 0; j < 10; j++)
{
work_orderp = (work_order_t *) malloc( sizeof(work_order_t));
work_orderp->index = j;
work_orderp->datap = i++;
work_orderp->listp = &my_list;

/************* Create a thread to insert an element in the list ******/

pthread_create(&(peer[j]), NULL, (void *)list_insert,
(void *)work_orderp);
}

/****** Wait for all the threads to finish ****/

for(i = 0; i < 10 ;i++)
{
pthread_join( peer[i], NULL);
}

list_show( my_list);
}


int list_init(list_t *listp)
{
listp->first = NULL;
pthread_mutex_init( &(listp->mutex), NULL);
return 1;
}


void list_insert( work_order_t *work_orderp)
{
list_insert_data( work_orderp->index, work_orderp->datap, *(work_orderp->listp));
free( work_orderp);

}

void list_insert_data( int index, int datap, list_t *listp)
{
list_node_t *cur, *prev, *new;
int found = 0;


pthread_mutex_lock( &(listp->mutex));

for(cur = prev = listp->first; cur != NULL; prev = cur, cur = cur->nextp)
{
if(cur->index == index) {
free (cur->datap);
cur->datap = datap;
found =1;
break;
}
else if(cur-> index > index)
break;
}


if( !found)
{
new = (list_node_t *) malloc( sizeof(list_node_t));
new->index = index;
new->datap = datap;
new->nextp= cur;
if( cur == listp->first)
listp->first = new;
else
prev->nextp = new;
}

pthread_mutex_unlock( &(listp->mutex));

}


/****** Print out the linked list **********/

void list_show( list_t *listp)
{

list_node_t *cur;

pthread_mutex_lock( &(listp->mutex));

for(cur = listp->first; cur != NULL; cur = cur->nextp)
{
printf("%d \t", cur->datap );
}

pthread_mutex_unlock( &(listp->mutex));
}