Threaded C programming using pthreads

C programming forum.

Threaded C programming using pthreads

Postby QuantumKnot on March 9th, 2008, 12:51 am

Since we're getting quad-cores soon, then it would be a good idea to get to know how to write programs that utilises threads so that we can exploit all cores, if need be. Linux uses the POSIX threading standard (pthreads) and the 2.6 kernel supports pthreads via RedHat's NPTL (Native POSIX Thread Library).

Here is a program I wrote that uses 2 threads to operate on an array of 10 numbers.

Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

struct Parameters {
   int threadNum;
   int *data;
   int N;
   int index;
   int sum;
};

void *threadWork(void *param);

int main(void)
{
   const int N = 10;
   int array[N];
   int i;
   pthread_t t1, t2;
   struct Parameters param1, param2;
   
   for (i = 0; i < N; i++)
      array[i] = i;
   
   // create thread to process first half of data
   param1.data = array;
   param1.N = 5;
   param1.index = 0;
   param1.threadNum = 0;
   pthread_create(&t1, NULL, threadWork, (void *)&param1);
   
   // create thread to process second half of data
   param2.data = array;
   param2.N = 5;
   param2.index = 5;
   param2.threadNum = 1;
   pthread_create(&t2, NULL, threadWork, (void *)&param2);
   
   pthread_join(t1, NULL);  // sleep the main() thread until thread 1 finishes
   pthread_join(t2, NULL);  // sleep the main() thread until thread 2 finishes
   
   printf("The sum is %d from thread 0 and %d from thread 1\n", param1.sum, param2.sum);
   
   for (i = 0; i < 10; i++)
      printf("%d ", array[i]);
   
   return (0);
}

void *threadWork(void *param)
{
   struct Parameters *p;
   int i;
   p = (struct Parameters *)param;
   printf("I am thread %d\n", p->threadNum);
   p->sum = 0;
   for (i = 0; i < p->N; i++) {
      p->sum += p->data[i + p->index];
      p->data[i + p->index] *= 2;
   }
   pthread_exit(NULL);
}


To compile, simply use:
Code: Select all
gcc threadTest.c -lpthread -o threadTest


Expected results:

Code: Select all
I am thread 0
I am thread 1
The sum is 10 from thread 0 and 35 from thread 1
0 2 4 6 8 10 12 14 16 18


Note that I haven't used any mutex's, which are used to lock up shared variables from being modified by other threads, since the data arrays operated on by both threads are mutually exclusive anyway.
Image
User avatar
QuantumKnot
Member
 
Posts: 99
Joined: January 21st, 2008, 11:58 am

Re: Simple C program using pthreads

Postby QuantumKnot on March 13th, 2008, 3:31 pm

To see your threads in top, type 'H'
To see your threads in ps, use the 'H' switch.

Code: Select all
% ps auxH | grep threads
stephen  21715  0.0  0.0  22324   468 ?        Sl   15:40   0:00 /home/stephen/Documents/workspace/threadsTest/Debug/threadsTest
stephen  21715  0.0  0.0  22324   468 ?        Sl   15:40   0:00 /home/stephen/Documents/workspace/threadsTest/Debug/threadsTest
stephen  21715  0.0  0.0  22324   468 ?        Sl   15:40   0:00 /home/stephen/Documents/workspace/threadsTest/Debug/threadsTest
stephen  21744  0.0  0.0   4048   684 pts/10   R+   15:40   0:00 grep threads
Image
User avatar
QuantumKnot
Member
 
Posts: 99
Joined: January 21st, 2008, 11:58 am

Re: Simple C program using pthreads

Postby kamil on March 13th, 2008, 6:14 pm

nice find... listing threads isn't that though afterall ;) when the new PCs arrive... I'll be sure to try your example :D
User avatar
kamil
Linux Adept
 
Posts: 118
Joined: January 18th, 2008, 1:22 am
Location: Brisbane, Australia

Re: Simple C program using pthreads

Postby QuantumKnot on March 14th, 2008, 10:56 pm

Here is an example of using mutexes to lock variables, which I adapted from Daniel Robbins' pthreads tutorial. The first program doesnt use mutexes:

Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *threadWork(void *data);

int count;

int main(void)
{
   pthread_t t1, t2;
   int i;
   
   count = 0;
   pthread_create(&t1, NULL, threadWork, NULL);
   pthread_create(&t2, NULL, threadWork, NULL);

   for (i = 0; i < 10; i++) {
      count++;
      printf(".");
      fflush(stdout);
   }

   pthread_join(t1, NULL);
   pthread_join(t2, NULL);
   
   printf("\ncount=%d\n", count);
   fflush(stdout);
   
   return (0);
}

void *threadWork(void *data)
{
   int i, c;
   
   for (i = 0; i < 10; i++) {
      c = count;
      c++;
      printf("o");
      fflush(stdout);
      sleep(1);
      count = c;
   }
   
   pthread_exit(NULL);
}


The output of this program is:

Code: Select all
oo..........oooooooooooooooooo
count=10


Note that each 'o' is the thread incrementing and a '.' indicates its the main thread incrementing. All 3 threads are incrementing the variable 'count', so the answer we expect is 30. But there is a race condition, where the thread copies count into a local variable, increments the local variable, sleeps, and writes it back. But during the sleeping, the main thread would have done its own incrementing to 10 but this gets overwritten by the threads.

Now we modify the program to use mutexes:

Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void *threadWork(void *data);

int count;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int main(void)
{
   pthread_t t1, t2;
   int i;
   
   count = 0;
   pthread_create(&t1, NULL, threadWork, NULL);
   pthread_create(&t2, NULL, threadWork, NULL);

   for (i = 0; i < 10; i++) {
      pthread_mutex_lock(&mutex);
      count++;
      pthread_mutex_unlock(&mutex);
      printf(".");
      fflush(stdout);
   }

   pthread_join(t1, NULL);
   pthread_join(t2, NULL);

   printf("\ncount=%d\n", count);
   fflush(stdout);
   
   return (0);
}

void *threadWork(void *data)
{
   int i, c;
   
   for (i = 0; i < 10; i++) {
      pthread_mutex_lock(&mutex);
      c = count;
      c++;
      printf("o");
      fflush(stdout);
      sleep(1);
      count = c;
      pthread_mutex_unlock(&mutex);
   }
   
   pthread_exit(NULL);
}


The results are now as expected:

Code: Select all
oooooooooo..........oooooooooo
count=30


One thread manages to lock the mutex which will block the other threads, preventing them from executing the code that modifies the global variable.
Image
User avatar
QuantumKnot
Member
 
Posts: 99
Joined: January 21st, 2008, 11:58 am


Return to C

Who is online

Users browsing this forum: No registered users and 0 guests

cron

dsplabs homelinux bloglinux forums new! travel photographyawklores new! cryptographyjames' home
©2009 dsplabs.com.au