Multithreading using C

28
Multithreading Multithreading using C Version 0.1 19 April 2011 © 2011 Faisal Khan - www.FaysalKhan.org licensed under the terms of the GNU Free Documentation License Version 1.3 or later

description

State of the art operating systems can run several processes in parallel. Besides this is a great thing, there are some disadvantages: slow context switch, overhead in communication between the processes. To take care of those problems, there are Threads.

Transcript of Multithreading using C

Page 1: Multithreading using C

MultithreadingMultithreading using C

Version 0.1 ● 19 April 2011

© 2011 Faisal Khan - www.FaysalKhan.org

licensed under the terms of the GNU Free Documentation License Version 1.3 or later

Page 2: Multithreading using C

Multithreading using C

Multithreading

VERSION: 0.1 REVISION DATE: 19 April 2011

Page 3: Multithreading using C

www.FaysalKhan.Org

Table Of Contents1. What is a Thread?................................................................................................................1

2. The Program......................................................................................................................... 2

3. Why is Synchronization needed?.........................................................................................5

4. Problems.............................................................................................................................. 6

5. What is a Mutex?.................................................................................................................. 7

6. The Program......................................................................................................................... 8

7. What are Condition Variables?...........................................................................................11

8. The Program.......................................................................................................................12

9. Exercises............................................................................................................................ 16

Related Books........................................................................................................................ 25

Multithreading 0.1 i

Page 4: Multithreading using C

www.FaysalKhan.Org

1. What is a Thread?State of the art operating systems can run several processes in parallel. Besides this is

a great thing, there are some disadvantages: slow context switch, overhead in

communication between the processes. To take care of those problems, there are

Threads.

Threads run within the context of a process and have the following characteristics:

1. They run concurrently.

2. They have no separate address space. They all use the context of the

surrounding process.

3. Thread switches are very fast because the CPU don't have to switch the

entire context of the process.

In fact, there is a disadvantage resulting from the points above: using processes the

operating system takes care of the address spaces, different from threads. Using

threads means that the programmer has to take care of starting, stopping even the

access to shared memory space. This makes a multithreaded program hard to debug,

but: it is fun!

There are two types of threads:

1. Usermode threads: run bound to one CPU

2. Kernelmode threads: run distributed over all CPUs in the system, if you have

a SMP system.

Let's have a look at a very first and simple program.

Multithreading 0.2 1

Page 5: Multithreading using C

www.FaysalKhan.Org

2. The ProgramFirst I'd like to have a look at a very simple program. It's so obvious what it does, I

don't think it needs any explanation.

0 #include <stdio.h>

1

2 void * work(void * ptr)

3 {

4 int i;

5 for (i = 0; i < 10; i++)

6 {

7 printf("%d", (int)ptr);

8 usleep(1000);

9 }

10 return 0;

11 }

12

13 int main(int argc, char ** argv)

14 {

15 work((void *)0);

16 work((void *)1);

17 return 0;

18 }

The program start, it calls the function work twice in series and terminates. The

function work prints the specified number 10 times and waits for 1 second after every

time. Just plain and simple.

Since this is a tutorial about multithreading, let's change the program in order to let

the function workd run at the same time instead of in series. To reach this goal we

have to do a few things (changes are marked bold):

0 #include <stdio.h>

1 #include <pthread.h>

2

3 void * work(void * ptr)

4 {

5 int i;

6 for (i = 0; i < 10; i++)

Multithreading 0.2 2

Page 6: Multithreading using C

www.FaysalKhan.Org

7 {

8 printf("%d", (int)ptr);

9 usleep(1000);

10 }

11 pthread_exit(0);

12 }

13

14 int main(int argc, char ** argv)

15 {

16 pthread_t t0, t1;

17

18 pthread_create(&t0, 0, work, (void *)0);

19 pthread_create(&t1, 0, work, (void *)1);

20

21 pthread_join(t0, 0);

22 pthread_join(t1, 0);

23 return 0;

24 }

2.1 Walk through

The first thing we've changed is to include another header on line 1. We need this

header in order to get able to use the pthreadlibrary.

1 #include <pthread.h>

The function work has only one change: the exit of the function (line 11). This is

needed to terminate the thread properly.

11 pthread_exit(0);

Most of the changes appear in the function main. To start the threads we have to

define an ID for each:

16 pthread_t t0, t1;

The second step is to create the threads. Please note: if you create a thread, it will run

immediately!

18 pthread_create(&t0, 0, work, (void *)0);

19 pthread_create(&t1, 0, work, (void *)1);

Have a look at the man pages for an explenation of all parameters. The two most

important are the first (the ID) and the third (the function to be called).

As mentioned in the introduction What is s Thread?, the programmer (as we are) has

to take care of the entire handling, including the proper termination. So we have two

choices:

Multithreading 0.2 3

Page 7: Multithreading using C

www.FaysalKhan.Org

1. wait for the created threads to terminate

2. detach the threads

We choose no. 1, for now. Ok, let's wait for the threads:

21 pthread_join(t0, 0);

22 pthread_join(t1, 0);

There we are! Our first multithreaded program. Frankly, it does nothing outstanding,

but it works and gives you a good access to the world of multithreading.

As mentioned before, I assume you to know how to compile and run C programs. So no

explanations here, sorry.

Multithreading 0.2 4

Page 8: Multithreading using C

www.FaysalKhan.Org

3. Why is Synchronization needed?Whenever two or more active parts have to share resources, sooner or later appear

conflicts about who uses when a shared resource. Synchronization of those active

parts makes it possible to control the access to the resources and lets run the

application stable and reliable.

Stability and reliability are very important attributes when it comes to let several

therads running concurrently. Assuming the mutual exclusion is guaranteed, there are

two problems we have to take care of:

1. Deadlock

2. indefinite Suspension

Read below to learn more about those problems.

Multithreading 0.2 5

Page 9: Multithreading using C

www.FaysalKhan.Org

4. ProblemsAs mentioned above there are several problems the programmer has to take care of.

This section covers those problems and how they can occur.

4.1 Deadlock

What is a deadlock? A deadlock is the situation in which all threads are blocked and

waiting for a resource. The picture below shows how this situation can happen:

Figure 1: an example of how a deadlock can happen.

The thread X holds the resource A, the thread Y holds the resource B. Now the

thread X wants to take the resource B and get blocked, because thread Y is already

using it. How comes, thread Y likes to get the resource A as well and get blocked too,

because thread X already holds it. This is a deadlock situation, because neither

thread X nor thread Y is able to continue its work.

It is necessary to avoid this situation at any cost. To gain performance at the cost of

the risk of a deadlock is a bad choice.

One possibility to avoid deadlock is to synchronize the threads and let them fetch the

resources using timeouts instead of blocking. This means that the thread which likes to

get the resource will fail after an amount of time. This means of course a good

exception/error handling.

4.2 Indefinite Suspension

Indefinite suspension can occur if one thread is of lower priority than another and the

scheduler run always the thread with the highest priority (not all schedulers do so). If

the high priority thread has a big workload, the lower priority thread does not get CPU

time any more, for an indefinite amount of time.

This is mostly an issue of design. A good design would be, that your program does run

(logically) even if you don't consider the priorities. They should only be for making

adjustments in response times (in theory).

Multithreading 0.2 6

Page 10: Multithreading using C

www.FaysalKhan.Org

5. What is a Mutex?A the name says: mutual exclusion is a mechanism to capsule a part of the program,

so called critical sections. It makes sure, that only one thread can be inside of a critical

section. Of course if there are several critical section, each guarded by a independent

mutex, it is possible to have a thread X in the section A and another thread Y in the

section B.

If a thread is within the critical section guarded by a mutex, it is called "the thread is

holding the mutex".

The consequence of that mechanism is, that the programmer should try to keep the

cirital sections as short and simple as possible. Not to respect this rule means a

possible (probably) loss of (a lot of) performance.

Mainly there are three operations on a mutex, which are used for daily business:

• lock: locks the mutex

• unlock: unlocks the mutex

• trylock: tries to lock the mutex, non-blocking function. If the mutex is already

locked, the function will return immediatly providing an error code. In the other

case, the mutex is locked and the thread may proceed.

The critical section usually looks like this:

1. lock the mutex

2. do the critical stuff

3. unlock the mutex

In most cases it is very useful to encapsulate the critical section within a separate

function. This enhances readability and maintainability.

Multithreading 0.2 7

Page 11: Multithreading using C

www.FaysalKhan.Org

6. The ProgramEnough for the theory, let's have a look at an example.

We start with the program we made in the last tutorial (thread1.c):

0 #include <stdio.h>

1 #include <pthread.h>

2

3 void * work(void * ptr)

4 {

5 int i;

6 for (i = 0; i < 10; i++)

7 {

8 printf("%d", (int)ptr);

9 usleep(1000);

10 }

11 pthread_exit(0);

12 }

13

14 int main(int argc, char ** argv)

15 {

16 pthread_t t0, t1;

17

18 pthread_create(&t0, 0, work, (void *)0);

19 pthread_create(&t1, 0, work, (void *)1);

20

21 pthread_join(t0, 0);

22 pthread_join(t1, 0);

23 return 0;

24 }

In the function work there is a printf statement which prints out the specified number

for the thread. Now we like to write more than one character. but since the

function printf is not thread safe, we have to take care of problem by ourselfes.

To reach our goal we're using a mutex (all changes to the original program are marked

bold):

0 #include <stdio.h>

1 #include <pthread.h>

2

Multithreading 0.2 8

Page 12: Multithreading using C

www.FaysalKhan.Org

3 pthread_mutex_t mtx;

4

5 void print(int thread, int i)

6 {

7 pthread_mutex_lock(&mtx);

8 printf("thread %d: %d\n", thread, i);

9 pthread_mutex_unlock(&mtx);

10 }

11

12 void * work(void * ptr)

13 {

14 int i;

15 for (i = 0; i < 10; i++)

16 {

17 print((int)ptr, i);

18 usleep(1000);

19 }

20 pthread_exit(0);

21 }

22

23 int main(int argc, char ** argv)

24 {

25 pthread_t t0, t1;

26

27 pthread_mutex_init(&mtx, 0);

28 pthread_create(&t0, 0, work, (void *)0);

29 pthread_create(&t1, 0, work, (void *)1);

30

31 pthread_join(t0, 0);

32 pthread_join(t1, 0);

33

34 pthread_mutex_destroy(&mtx);

35 return 0;

36 }

6.1 Walkthrough

First, we have to define a mutex variable for further use.

3 pthread_mutex_t mtx;

Multithreading 0.2 9

Page 13: Multithreading using C

www.FaysalKhan.Org

Since we like to encapsulate the critical section within a separate function to increase

readability, let's do so and we have to protect the critical section with locking and

unlocking the mutex:

5 void print(int thread, int i)

6 {

7 pthread_mutex_lock(&mtx);

8 printf("thread %d: %d\n", thread, i);

9 pthread_mutex_unlock(&mtx);

10 }

The thread function a small change to according to the separated critical section:

17 print((int)ptr, i);

All there is left to do is within the function main to take care of the initialisation

27 pthread_mutex_init(&mtx, 0);

and the destruction of the mutex variable:

34 pthread_mutex_destroy(&mtx);

Multithreading 0.2 10

Page 14: Multithreading using C

www.FaysalKhan.Org

7. What are Condition Variables?Condition variables are a very elegant way to do some synchronization. A thread can

wait for a condition becoming true to continue and a thread can also make a condition

come true. Since a thread is an active part, it can wait for or make a condition which

are others waiting for.

Let's have a look at an example (see figure 1 below). Thread X creates an item and

stores it. Thread Y is waiting for the item to process it. Now let's say: "thread X is

making a condition for thread Y to get to work."

Figure 1: making and waiting for a condition.

We will have a look at an implementation of this example below.

Multithreading 0.2 11

Page 15: Multithreading using C

www.FaysalKhan.Org

8. The ProgramThis is the entire source code of the example. For a walk through, please read below.

The following program is a very simple producer-consumer demo. It shows two

threads, one that produces some numbers, the second that consumes them. The demo

is simple because we only use one place as buffer between those threads. So every

time the producer has an item, it has to wait for the consumer to take it. To tell the

consumer (sending a signal), that an item is ready we use the condition variable.

As soon as the ten items are produced and consumed, the threads will stop and the

demo will end.

0 #include <stdio.h>

1 #include <pthread.h>

2

3 pthread_mutex_t mtx;

4 pthread_cond_t cond;

5

6 int how_many = 10;

7 int pool = 0;

8

9 void * producer(void * ptr)

10 {

11 while (how_many > 0)

12 {

13 pthread_mutex_lock(&mtx);

14 printf("producer: %d\n", how_many);

15 pool = how_many;

16 how_many--;

17 pthread_mutex_unlock(&mtx);

18 pthread_cond_signal(&cond);

19 }

20 pthread_exit(0);

21 }

22

23 void * consumer(void * ptr)

24 {

25 while (how_many > 0)

26 {

27 pthread_mutex_lock(&mtx);

Multithreading 0.2 12

Page 16: Multithreading using C

www.FaysalKhan.Org

28 pthread_cond_wait(&cond, &mtx);

29 printf("consumer: %d\n", pool);

30 pool = 0;

31 pthread_mutex_unlock(&mtx);

32 }

33 pthread_exit(0);

34 }

35

36 int main(int argc, char ** argv)

37 {

38 pthread_t prod, cons;

39 pthread_mutex_init(&mtx, 0);

40 pthread_cond_init(&cond, 0);

41 pthread_create(&cons, 0, consumer, 0);

42 pthread_create(&prod, 0, producer, 0);

43 pthread_join(prod, 0);

44 pthread_join(cons, 0);

45 pthread_cond_destroy(&cond);

46 pthread_mutex_destroy(&mtx);

47 return 0;

48 }

8.1 Walkthrough

The first part is plain simple header inclusion.

0 #include <stdio.h>

1 #include <pthread.h>

Next we have to define some global variables. Global variables are not my favorite,

but they will do for this example program. My usually advise: Do not use global

data! Ok, the data we need is a mutex and a condition variable.

3 pthread_mutex_t mtx;

4 pthread_cond_t cond;

We also need some variables which take data for the simple producer-consumer demo.

6 int how_many = 10;

7 int pool = 0;

Next we'll have a look at the consumer:

9 void * producer(void * ptr)

10 {

11 while (how_many > 0)

12 {

Multithreading 0.2 13

Page 17: Multithreading using C

www.FaysalKhan.Org

13 pthread_mutex_lock(&mtx);

14 printf("producer: %d\n", how_many);

15 pool = how_many;

16 how_many--;

17 pthread_mutex_unlock(&mtx);

Nothing special so far. The thread locks the mutex to enter the critical section, prints

out which item has been produced, stores it in the pool and decreases the total

number of item to produce in the future. The last step is to unlock the mutex; to exit

the critical section.

The new thing we're looking at in this tutorial is the condition variable and their

handling. So far we didn't really used the condition variable at all, but now we have to

send a signal that the pool is full:

18 pthread_cond_signal(&cond);

What now follows is the usual thread termination statement.

19 }

20 pthread_exit(0);

21 }

Let's have a look at the consumer.

23 void * consumer(void * ptr)

24 {

25 while (how_many > 0)

26 {

27 pthread_mutex_lock(&mtx);

So far, there's nothing special, locking the mutex to enter the critical section is

standard procedure. Now appears the question, what if there aren't any produced

items yet? Here comes the answer: the condition variable that we are waiting for.

28 pthread_cond_wait(&cond, &mtx);

This statement will unlock the mutex until the condition gets true, say a signal has

been sent. Then the mutex gets locked again (using pthread_mutex_lock, so no

timeout), and the thread continues into the critical section.

29 printf("consumer: %d\n", pool);

30 pool = 0;

31 pthread_mutex_unlock(&mtx);

32 }

33 pthread_exit(0);

34 }

The rest of the function is quite normal: printing the data from the pool, resetting the

pool and unlocking the mutex, exiting the critical section.

Multithreading 0.2 14

Page 18: Multithreading using C

www.FaysalKhan.Org

Last but not least, standard procedure to terminate the thread.

The function main is quite normal too. The only difference are the initialisation and the

destruction of the condition variable.

Please note: the consumer thread is started first, so it can start to consume as soon as

there are items ready. This is a measure of quality, not to run the producer first.

36 int main(int argc, char ** argv)

37 {

38 pthread_t prod, cons;

39 pthread_mutex_init(&mtx, 0);

40 pthread_cond_init(&cond, 0);

41 pthread_create(&cons, 0, consumer, 0);

42 pthread_create(&prod, 0, producer, 0);

43 pthread_join(prod, 0);

44 pthread_join(cons, 0);

45 pthread_cond_destroy(&cond);

46 pthread_mutex_destroy(&mtx);

47 return 0;

48 }

Multithreading 0.2 15

Page 19: Multithreading using C

www.FaysalKhan.Org

9. ExercisesMultithreading is fun, isn't it? Go ahead try to implement a producer-consumer system:

a. using a circular buffer (queue) with more than one space

b. using more than one producer

c. using more than one consumer

d. using a queue larger than 1, using multiple producers and consumers

9.1 Solutions

The solution provided here is not the only one possible implementations. The are many

solutions. This ones should give you a hint or if you like to compare your solution with

this ones.

a.

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#define POOL_SIZE 3

typedef struct

{

int data[POOL_SIZE];

int start;

int end;

int count;

} pool_t;

int num_of_items = 10;

pthread_mutex_t mtx;

pthread_cond_t cond_nonempty;

pthread_cond_t cond_nonfull;

pool_t pool;

void init_pool(pool_t * pool)

{

pool->start = 0;

pool->end = -1;

pool->count = 0;

Multithreading 0.2 16

Page 20: Multithreading using C

www.FaysalKhan.Org

}

void push(pool_t * pool, int data)

{

pthread_mutex_lock(&mtx);

while (pool->count >= POOL_SIZE)

{

pthread_cond_wait(&cond_nonfull, &mtx);

}

pool->end = (pool->end + 1) % POOL_SIZE;

pool->data[pool->end] = data;

pool->count++;

pthread_mutex_unlock(&mtx);

}

int pop(pool_t * pool)

{

int data = 0;

pthread_mutex_lock(&mtx);

while (pool->count <= 0)

{

pthread_cond_wait(&cond_nonempty, &mtx);

}

data = pool->data[pool->start];

pool->start = (pool->start + 1) % POOL_SIZE;

pool->count--;

pthread_mutex_unlock(&mtx);

return data;

}

void * producer(void * ptr)

{

while (num_of_items > 0)

{

push(&pool, num_of_items);

printf("producer: %d\n", num_of_items);

num_of_items--;

pthread_cond_broadcast(&cond_nonempty);

}

pthread_exit(0);

}

Multithreading 0.2 17

Page 21: Multithreading using C

www.FaysalKhan.Org

void * consumer(void * ptr)

{

while (num_of_items > 0 || pool.count > 0)

{

printf("consumer: %d\n", pop(&pool));

pthread_cond_broadcast(&cond_nonfull);

usleep(500000);

}

pthread_exit(0);

}

int main(int argc, char ** argv)

{

pthread_t cons, prod;

init_pool(&pool);

pthread_mutex_init(&mtx, 0);

pthread_cond_init(&cond_nonempty, 0);

pthread_cond_init(&cond_nonfull, 0);

pthread_create(&cons, 0, consumer, 0);

pthread_create(&prod, 0, producer, 0);

pthread_join(prod, 0);

pthread_join(cons, 0);

pthread_cond_destroy(&cond_nonempty);

pthread_cond_destroy(&cond_nonfull);

pthread_mutex_destroy(&mtx);

return 0;

}

b.

#include <stdio.h>

#include <pthread.h>

#define FULL 1

#define EMPTY 0

pthread_mutex_t mtx_item;

pthread_mutex_t mtx;

pthread_cond_t cond_nonempty;

pthread_cond_t cond_nonfull;

Multithreading 0.2 18

Page 22: Multithreading using C

www.FaysalKhan.Org

int how_many = 10;

int pool = 0;

int pool_state = EMPTY;

int produce_one(void)

{

int result = -1;

pthread_mutex_lock(&mtx_item);

result = how_many--;

pthread_mutex_unlock(&mtx_item);

return result;

}

void push(int data)

{

pthread_mutex_lock(&mtx);

while (pool_state == FULL) pthread_cond_wait(&cond_nonfull, &mtx);

pool = data;

pool_state = FULL;

pthread_mutex_unlock(&mtx);

}

int pop(void)

{

int data;

pthread_mutex_lock(&mtx);

while (pool_state == EMPTY)

{

if (how_many <= 0)

{

pthread_mutex_unlock(&mtx);

return -1;

}

pthread_cond_wait(&cond_nonempty, &mtx);

}

data = pool;

pool_state = EMPTY;

pthread_mutex_unlock(&mtx);

return data;

}

Multithreading 0.2 19

Page 23: Multithreading using C

www.FaysalKhan.Org

void * producer(void * ptr)

{

int data;

while (how_many > 0)

{

data = produce_one();

printf("producer<%d>: %d\n", (int)ptr, data);

push(data);

pthread_cond_broadcast(&cond_nonempty);

}

pthread_exit(0);

}

void * consumer(void * ptr)

{

while (how_many > 0 || pool_state != EMPTY)

{

printf("consumer<%d>: %d\n", (int)ptr, pop());

pthread_cond_broadcast(&cond_nonfull);

}

pthread_exit(0);

}

int main(int argc, char ** argv)

{

pthread_t prod, cons0, cons1;

pthread_mutex_init(&mtx_item, 0);

pthread_mutex_init(&mtx, 0);

pthread_cond_init(&cond_nonempty, 0);

pthread_cond_init(&cond_nonfull, 0);

pthread_create(&cons0, 0, consumer, (void *)0);

pthread_create(&cons1, 0, consumer, (void *)1);

pthread_create(&prod, 0, producer, (void *)0);

pthread_join(prod, 0);

pthread_join(cons0, 0);

pthread_join(cons1, 0);

pthread_cond_destroy(&cond_nonempty);

pthread_cond_destroy(&cond_nonfull);

pthread_mutex_destroy(&mtx);

Multithreading 0.2 20

Page 24: Multithreading using C

www.FaysalKhan.Org

pthread_mutex_destroy(&mtx_item);

return 0;

}

c.

#include <stdio.h>

#include <pthread.h>

#include <unistd.h>

#include <time.h>

#define POOL_SIZE (3)

typedef struct

{

int data[POOL_SIZE];

int start;

int end;

int count;

} pool_t;

int items_to_produce = 20;

pthread_mutex_t mtx;

pthread_mutex_t mtx_item_prod;

pthread_cond_t cond_nonempty;

pthread_cond_t cond_nonfull;

pool_t pool;

void init_pool(pool_t * pool)

{

pool->start = 0;

pool->end = -1;

pool->count = 0;

}

void push(pool_t * pool, int data)

{

pthread_mutex_lock(&mtx);

while (pool->count >= POOL_SIZE) {

pthread_cond_wait(&cond_nonfull, &mtx);

}

Multithreading 0.2 21

Page 25: Multithreading using C

www.FaysalKhan.Org

pool->end = (pool->end + 1) % POOL_SIZE;

pool->data[pool->end] = data;

pool->count++;

pthread_mutex_unlock(&mtx);

}

int pop(pool_t * pool)

{

int data = 0;

pthread_mutex_lock(&mtx);

while (pool->count <= 0) {

pthread_cond_wait(&cond_nonempty, &mtx);

}

data = pool->data[pool->start];

pool->start = (pool->start + 1) % POOL_SIZE;

pool->count--;

pthread_mutex_unlock(&mtx);

return data;

}

int size(pool_t * pool)

{

int result = 0;

pthread_mutex_lock(&mtx);

result = pool->count;

pthread_mutex_unlock(&mtx);

return result;

}

int produce_one(void)

{

int result = -1;

pthread_mutex_lock(&mtx_item_prod);

result = items_to_produce--;

pthread_mutex_unlock(&mtx_item_prod);

return result;

}

int has_more_to_produce(void)

{

int result = 0;

Multithreading 0.2 22

Page 26: Multithreading using C

www.FaysalKhan.Org

pthread_mutex_lock(&mtx_item_prod);

result = (items_to_produce > 0);

pthread_mutex_unlock(&mtx_item_prod);

return result;

}

void * producer(void * ptr)

{

int data;

while (has_more_to_produce()) {

data = produce_one();

printf("producer %d : %d\n", (int)ptr, data);

push(&pool, data);

pthread_cond_broadcast(&cond_nonempty);

usleep(500 + (rand() % 500)); // slow down for demonstration

}

pthread_exit(0);

}

void * consumer(void * ptr)

{

while (items_to_produce > 0 || size(&pool) > 0) {

printf("consumer %d : %d\n", (int)ptr, pop(&pool));

pthread_cond_broadcast(&cond_nonfull);

usleep(1000 + (rand() % 2000)); // slow down for demonstration

}

pthread_exit(0);

}

int main(int argc, char ** argv)

{

pthread_t cons0, cons1, cons2; // three consumers

pthread_t prod0, prod1; // two producers

// initialize pseudo random generator

srand((unsigned int)time(0));

// initialize buffer related stuff

init_pool(&pool);

pthread_mutex_init(&mtx, 0);

pthread_cond_init(&cond_nonempty, 0);

Multithreading 0.2 23

Page 27: Multithreading using C

www.FaysalKhan.Org

pthread_cond_init(&cond_nonfull, 0);

// create multiple consumers, waiting for data

pthread_create(&cons0, 0, consumer, (void *)0);

pthread_create(&cons1, 0, consumer, (void *)1);

pthread_create(&cons2, 0, consumer, (void *)2);

// create multiple producers

pthread_mutex_init(&mtx_item_prod, 0);

pthread_create(&prod0, 0, producer, (void *)0);

pthread_create(&prod1, 0, producer, (void *)1);

// wait for all threads to terminate

pthread_join(prod0, 0);

pthread_join(prod1, 0);

// clean up buffer related stuff

pthread_cond_destroy(&cond_nonempty);

pthread_cond_destroy(&cond_nonfull);

pthread_mutex_destroy(&mtx);

// consumers get automatically terminated in this example

return 0;

}

Multithreading 0.2 24

Page 28: Multithreading using C

www.FaysalKhan.Org

Related Books• Windows via C/C++ by Jeffrey M. Richter and Christopher Nasarre. (The book is not

only about multithreading but has got a good section devoted to it.)

• Effective Concurrency by Herb Sutter.

• C++ Concurrency in Action by Anthony Williams.

• Programming with POSIX Threads by David R. Butenhof.

• Multithreaded Programming in C++ by Mark Walmsley.

• Concurrent Programming on Windows by Joe Duffy.

Multithreading 0.2 25