LAB - 5-Threading Using Pthreads API
LAB - 5-Threading Using Pthreads API
Figure 1
Recall that fork() also creates a child process, but the child process has its own address space. Threads are
considered lightweight processes because they share the same address space of the parent process as
shown in Fig. 01. As a result threads have advantages over child processes created through fork() such as
quick creation and termination, quicker context switching, less communication overhead between
threads.
C provides an API called Pthreads to create and destroy threads. Observe the following program. The
program only
pthread_detach(pthread_self());
Page 1 of 8
printf("Hello from new thread - got %d\n", my_data);
exit(1);
How it works
- In main(), a variable called thread_id is declared, which is of type pthread_t. This is an integer
value used to identify the thread in the system.
- After declaring thread_id, we call the pthread_create() function to create a real, living thread. It
takes 4 arguments.
o The first argument is a pointer to thread_id that supplies the program with the thread's
identifier.
Page 2 of 8
o The second argument is used to set some attributes for the new thread. The NULL pointer
uses the default values.
o The third argument is the main function for the thread; the thread begins executing user
code at this address. In this case it is the function called PrintHello().
o Notice that PrintHello() accepts a void * as an argument and also returns a void * as a
return value. This shows us that it is possible to use a void * to pass an arbitrary piece of
data to our new thread, and that our new thread can return an arbitrary piece of data
when it finishes. How do we pass our thread an arbitrary argument? We use the fourth
argument to the pthread_create() call. If we do not want to pass any data to the new
thread, we set the fourth argument to NULL. pthread_create() returns zero on success
and a non-zero value on failure.
- If the pthread_create() returns successfully, then the program consists of two threads. This is
because the main program is also a thread and it executes the code in the main() function in
parallel to the thread it creates.
- The call to pthread_exit causes the current thread to exit and free any thread-specific resources
it is taking.
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#define NUM_THREADS 5
struct thread_data {
int thread_id;
char *message;
};
Page 3 of 8
void *PrintHello(void *threadarg) {
pthread_exit(NULL);
int main () {
pthread_t threads[NUM_THREADS];
int rc;
int i;
td[i].thread_id = i;
if (rc) {
exit(-1);
pthread_exit(NULL);
Page 4 of 8
}
Now that you have created threads and passed structures as arguments to the threads, your task is to
understand the code below and submit a line-by-line explanation of the program to show how thread
pools are implemented.
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define THREAD_NUM 4
int a, b;
} Task;
Task taskQueue[256];
int taskCount = 0;
pthread_mutex_t mutexQueue;
pthread_cond_t condQueue;
Page 5 of 8
usleep(50000);
pthread_mutex_lock(&mutexQueue);
taskQueue[taskCount] = task;
taskCount++;
pthread_mutex_unlock(&mutexQueue);
pthread_cond_signal(&condQueue);
// 1 2 3 4 5
// 2 3 4 5
while (1) {
Task task;
pthread_mutex_lock(&mutexQueue);
while (taskCount == 0) {
pthread_cond_wait(&condQueue, &mutexQueue);
task = taskQueue[0];
int i;
Page 6 of 8
}
taskCount--;
pthread_mutex_unlock(&mutexQueue);
executeTask(&task);
pthread_t th[THREAD_NUM];
pthread_mutex_init(&mutexQueue, NULL);
pthread_cond_init(&condQueue, NULL);
int i;
srand(time(NULL));
Task t = {
.a = rand() % 100,
.b = rand() % 100
};
submitTask(t);
if (pthread_join(th[i], NULL) != 0) {
Page 7 of 8
perror("Failed to join the thread");
pthread_mutex_destroy(&mutexQueue);
pthread_cond_destroy(&condQueue);
return 0;
Page 8 of 8