$30
A thread is a semi-process, which has its own stack, and executes a given piece of code. Unlike a real process, the thread normally shares its memory with other threads (whereas for processes we usually have a different memory area for each one of them). A Thread Group is a set of threads all executing inside the same process. They all share the same memory, and thus can access the same global variables, same heap memory, same set of file descriptors, etc. All these threads execute in parallel (i.e. using time slices, or if the system has several processors, then really in parallel).
Pthreads are defined as a set of C language programming types and procedure calls. Vendors usually provide a Pthreads implementation in the form of a header/include file and a library, which you link with your program.
Demo Codes
Demo 1
#include <pthread.h
#include <stdio.h
#define NUM_THREADS 5
void* printHello(void *threadId)
{
printf("\n%d:Hello World!\n",threadId); pthread_exit(NULL);
}
int main()
{
pthread_t threads[NUM_THREADS]; int rc,t;
for(t=0;t<NUM_THREADS;t++)
{ printf("Creating thread %d\n",t);
rc = pthread_create(&threads[t],NULL,printHello,(void*)t); if(rc){
printf("ERROR:Return Code from pthread_create() is %d\n",rc);
}
}
pthread_exit(NULL);
}
You can also define a global variable such that it is thread-specific. The variable is global, but the value it holds will be thread specific. In the snippet below, the modifier __thread defines the variable myData as Thread Local Storage.
#include statements __thread int myData ; void *threadFunc ()
{
//access and modification of data “myData” will be local
}
int main ()
{
//create and launch threads
//join threads
}
There is another way to achieve the same thing. Here you can use pthread_key_t as the modifier.
#include statements pthread_key_t myKey;
void* threadFunc()
{
int* data = malloc(sizeof(int));
//this modification is thread specific pthread_setspecific(myKey,data);
//access the data using following
// the real use for this is when you need to access it from another function, but want it to be specific to a thread int* myLoc = pthread_getspecific(myKey);
} int main()
{
pthread_key_create(&myKey,NULL);
//create and launch threads
//join threads
}
Demo 2
/*
Written By: Prawar Poudel
13 Feb 2018
This is written to demonstrate simple creation and waiting for pthread to terminate
*/
#include <pthread.h
#include <stdio.h
#include <unistd.h
#define NUM_THREADS 5
//the argument that will be sent will be the (int) id void *simpleThreadFunc(void* argument)
{
int myId = (int)argument; printf("My Id is %d\n",myId);
int a = 0;
}
int main()
{
//you can create these dynamically also pthread_t myThreads[NUM_THREADS];
int status = 0;
for(int i=0;i<NUM_THREADS;i++)
{
printf("Creating thread no. %d, and sending ID %d\n",i,i); status = pthread_create(&myThreads[i],NULL,simpleThreadFunc,(void*)i); if(status)
{
printf("Error in creating the threads: %d\n",i); return -1;
}else
{
printf("Successful creation of thread..\n");
}
}
//this is the area that threads will run
//we will wait for the threads here for(int i=0;i<NUM_THREADS;i++)
{ int retStatus = pthread_join(myThreads[i],NULL); if(!retStatus)
{
printf("Successful termination of thread id %d\n",i); }else
printf("Well..... some problem at thread id %d, error no: %d\n",i,retStatus);
}
return 0;
}
Demo 3
/*
Written By: Prawar Poudel
13 Feb 2018
This is written to demonstrate simple creation and waiting for pthread to terminate
*/
#include <pthread.h
#include <stdio.h
#include <unistd.h
#define NUM_THREADS 100
int mutexProtectedGlobalVariable; int unprotectedProtectedGlobalVariable; pthread_mutex_t myMutex;
//this function will update the value without any protection void *unprotectedThreadFunc(void* argument)
{
for(int i=0;i<10000;i++) unprotectedProtectedGlobalVariable++; }
//this function will update the value without any protection void *protectedThreadFunc(void* argument)
{
pthread_mutex_lock (&myMutex);
for(int i=0;i<10000;i++) mutexProtectedGlobalVariable++; pthread_mutex_unlock (&myMutex);
}
int main()
{
mutexProtectedGlobalVariable = 0; unprotectedProtectedGlobalVariable = 0;
//you can create these dynamically also pthread_t myThreads[NUM_THREADS];
int status = 0;
printf("Calling unprotected set of threads\n");
//first set of five threads will call a function that will update the variable unprotected for(int i=0;i<NUM_THREADS;i++)
{
status = pthread_create(&myThreads[i],NULL,unprotectedThreadFunc, (void*)i); if(status)
{
printf("Error in creating the threads: %d\n",i); return -1;
}
}
//this is the area that threads will run
//we will wait for the threads here for(int i=0;i<NUM_THREADS;i++)
{ int retStatus = pthread_join(myThreads[i],NULL); if(retStatus)
{
printf("Well..... some problem at thread id %d, error no: %d\n",i ,retStatus );
}
}
printf("Unprotected sum is %d\n", unprotectedProtectedGlobalVariable); printf("\t\t...end of unprotected set of threads\n");
printf("Calling protected set of threads\n"); pthread_mutex_init(&myMutex, NULL);
//next set of five threads will call a function that will update the variable protected for(int i=0;i<NUM_THREADS;i++)
{ status = pthread_create(&myThreads[i],NULL,protectedThreadFunc, (void*)i); if(status)
{
printf("Error in creating the threads: %d\n",i); return -1;
}
}
//this is the area that threads will run
//we will wait for the threads here for(int i=0;i<NUM_THREADS;i++)
{ int retStatus = pthread_join(myThreads[i],NULL); if(retStatus) {
printf("Well..... some problem at thread id %d, error no: %d\n",i,retStatus);
}
}
pthread_mutex_destroy(&myMutex); printf("Protected sum is %d \n", mutexProtectedGlobalVariable); printf("\t\t...end of unprotected set of threads\n");
return 0;
}
Demo 4
/*
Written By: Prawar Poudel
13 Feb 2018
This is written to demonstrate the usage of Thread Local Storage Here using identifier __thread , we have made myVal and myArr[] thread local */
#include <pthread.h
#include <stdio.h
#include <unistd.h
#define NUM_THREADS 5 #define ARRSIZE 5
//this value is a global variable,
// but we will store it as thread local, meaning while it is still global the value will can be modified such that the modified value is thread specific __thread int myVal;
__thread int myArr[ARRSIZE];
void printMyVal(int id)
{
printf("My value myVal from thread %d is %d\n", id,myVal); printf("My arr value are\n"); for(int i=0;i<ARRSIZE;i++)
{
printf("%dthe element is %d\n",i,myArr[i]);
} }
//the argument that will be sent will be the (int) id void *simpleThreadFunc(void* argument)
{
int myId = (int)argument; printf("My Id is %d\n",myId);
//just setting some thread specific value to the variable myVal = myId*100;
for(int i=0;i<5;i++)
myArr[i] = (myId*100+i);
printMyVal(myId);
}
int main()
{
//you can create these dynamically also pthread_t myThreads[NUM_THREADS];
int status = 0;
for(int i=0;i<NUM_THREADS;i++)
{
printf("Creating thread no. %d, and sending ID %d\n",i,i); status = pthread_create(&myThreads[i],NULL,simpleThreadFunc,(void*)i); if(status)
{
printf("Error in creating the threads: %d\n",i); return -1;
}else
{
printf("Successful creation of thread..\n");
}
}
//this is the area that threads will run
//we will wait for the threads here for(int i=0;i<NUM_THREADS;i++)
{ int retStatus = pthread_join(myThreads[i],NULL); if(!retStatus)
{
printf("Successful termination of thread id %d\n",i); }else
printf("Well..... some problem at thread id %d, error no: %d\n",i,retStatus);
}
return 0;
}
Demo 5
/*
Written By: Prawar Poudel
13 Feb 2018
This is written to demonstrate the usage of Thread Local Storage using key */
#include <pthread.h
#include <stdio.h
#include <unistd.h
#define NUM_THREADS 5
#define ARRSIZE 5
//in this program we will use a key defined by pthread_key_t to define a key pthread_key_t myKey;
void printMyVal(int myId)
{
printf("Getting specific value for thread %d using key\n",myId); int *myVal = pthread_getspecific(myKey);
printf("\t..The thread local value in thread id %d is %d\n",myId,*myVal); }
//the argument that will be sent will be the (int) id void *simpleThreadFunc(void* argument)
{
int myId = (int)argument;
//this variable will be thread specific value that we will print from other function int myVal = myId*100;
printf("Creating the variable ::%d that will be referred to by Key from threadid
%d\n",myVal,myId);
if(!pthread_setspecific(myKey,(void*)&myVal)) {}else
{
printf("Erorr in setting specific key in thread id %d\n",myId); }
printMyVal(myId);
}
int main()
{
//you can create these dynamically also pthread_t myThreads[NUM_THREADS]; int status = 0;
pthread_key_create(&myKey,NULL);
for(int i=0;i<NUM_THREADS;i++)
{
printf("Creating thread no. %d, and sending ID %d\n",i,i); status = pthread_create(&myThreads[i],NULL,simpleThreadFunc,(void*)i); if(status)
{
printf("Error in creating the threads: %d\n",i); return -1;
}else
{
printf("Successful creation of thread %d..\n",i);
}
}
//this is the area that threads will run
//we will wait for the threads here for(int i=0;i<NUM_THREADS;i++)
{ int retStatus = pthread_join(myThreads[i],NULL); if(!retStatus)
{
printf("Successful termination of thread id %d\n",i); }else
printf("Well..... some problem at thread id %d, error no: %d\n",i,retStatus);
}
return 0;
}
Assignment
Write a parallel program to compute the definite integral using Rectangular decomposition:
Write a program in a general pthreads manner, so that they can utilize an arbitrary number of threads so the computation is divided among these computational entities as evenly as possible. Design program so that the number of intervals and the number of operating threads can be entered as a run time parameter (ie command line argument) by the user under the constraint that it must be greater than or equal to the number of threads that are used. Plot the execution time taken by 100,000 intervals with 1, 2, 4, 8 and 16 threads.
You are expected to do the following tasks:
Write a serial code version to compute integral, using a timing function to evaluate its execution time .
Write a parallel version of code using pthreads model, compare the result and execution time.
Compare the performance of two models (serial and pthreads ). Try different number of intervals by increasing the number. Show graph to summary the execution time of the two models versus different number of intervals (ie 1,000, 10,000 and 100,000 intervals with serial vs parallel with 2 threads only.)
Compare the performance of the serial model and parallel based on the execution time. (ie. 100,000 intervals with serial vs parallel with 1, 2, 4, 8 and 16 threads)