Multithreading--Semaphores

Hi All,
I have come across below code to demenostrate the use of semaphores

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>

#define NITER 1000000

int count = 0;

void * ThreadAdd(void * a)
{
    int i, tmp;
    for(i = 0; i < NITER; i++)
    {
        tmp = count;      /* copy the global count locally */
        tmp = tmp+1;      /* increment the local copy */
        count = tmp;      /* store the local value into the global count */ 
    }
}

int main(int argc, char * argv[])
{
    pthread_t tid1, tid2;

    if(pthread_create(&tid1, NULL, ThreadAdd, NULL))
    {
      printf("\n ERROR creating thread 1");
      exit(1);
    }

    if(pthread_create(&tid2, NULL, ThreadAdd, NULL))
    {
      printf("\n ERROR creating thread 2");
      exit(1);
    }

    if(pthread_join(tid1, NULL))	/* wait for the thread 1 to finish */
    {
      printf("\n ERROR joining thread");
      exit(1);
    }

    if(pthread_join(tid2, NULL))        /* wait for the thread 2 to finish */
    {
      printf("\n ERROR joining thread");
      exit(1);
    }

    if (count < 2 * NITER) 
        printf("\n BOOM! count is [%d], should be %d\n", count, 2*NITER);
    else
        printf("\n OK! count is [%d]\n", count);
  
    pthread_exit(NULL);
}


My question is:

why the question of syncronising threads and mutexes and semaphores come into the picture when we join threads?

Like in the above example we have joined the first thread and then second thread so that main process will pause for the first thread to finish as its joined and then main process resumes and gives control to second thread and pauses till its finished as this thread is also joined.


Then where is question of simeltaneous access?

First thread does its job and ends itself.
second thread does its job and ends itself.

I wonder why there is need to use semaphores or mutexes in this example?
Please help me understand if mutexes,semaphores and condition variables are different ways of achieving synchronisation or they are used for different purposes when it comes to synchronisation?


I am very new to Multithreading and this question bothers me as to why we have to worry about simeltaneous access when we can join threads and can make control wait till that thread ends?


Thanks in advance and very sorry to type long mail.
This is a big question ^.^

When you have multiple threads (and you're running your program on a cpu with multiple cores) then those threads probably run parallel doing their stuff.
Especially they do memory requests. More especially - In the example above both threads use the global variable count.
Running this code you should run into run-time errors due to simultaneous count-variable access from both threads. It simply is not allowed that 2 Threads can read or write from/to the same memory space (in this example count).

This means to avoid those "fancy word: "race-conditions" " we have to make sure only one thread is allowed to access count at a certain time.

This leads to Mutexes.
With a Mutex a Thread accessing "count" can block all other Threads so they cannot do that at the same time.

Haven't used pthreads in a long time so Imma just show u in kinda "pseudo-code" in your example:

1
2
3
4
5
6
7
8
9
10
11
12
    
for(i = 0; i < NITER; i++)
{
"Mutex.lock"   /*When a thread arrives here he "locks" this mutex 
which means every other thread will wait here until it is "unlocked" */
// Then we do the following three lines without worrying another thread reads count as well
tmp = count;    
tmp = tmp+1;    
count = tmp;      
"Mutex.unlock"   /*Once our thread who arrived above first finished this "fancy word:"critcial region" "
 we "unlock" the mutex which lets another Thread in obove at "Mutex.lock" */
    }


Basicly all we do is we ensure that only one thread at a time is allowed to do
tmp = count;
tmp = tmp+1;
count = tmp;

More general: We only allowed one thread at a time to read/write from/to count - thus we don't get a run-time error

Semaphore is something similar to Mutex but that might be enough for now ;>

Now to your code: Once your main "Thread" (what you called "main process", that's not the right description, 'cause there is all the time just one process, but many threads (in your case at max 3) creates those 2 Threads they both will run simultaneously.

thread.join() simply means that at this point the "main Thread" is supposed to wait until the thread finished (yes we wait for thread1 first but thread2 is also running.)

I hope pthreads are automaticlly started when you "create" them. Sometimes you also have to call "thread.launch()" or something similar.

Well I probably forgot something - just keep asking ^.^
Last edited on
@@Glandy
Thanks for clarification and I have one more question :)

I was assuming that main thread will wait till thread1 completely finishes its job before it spawns thread2
as we have joined thread1 and thread2 to main thread.

As you said these two threads will execute simeltaneously....then what is use of using pthread_join?

what will happen if i exclude below code from the program mentioned above?will it result in any changes in the way these 3 threads work( main thread,thread1 and thread2)?

i
1
2
3
4
5
6
7
8
9
10
11
f(pthread_join(tid1, NULL))	/* wait for the thread 1 to finish */
    {
      printf("\n ERROR joining thread");
      exit(1);
    }

    if(pthread_join(tid2, NULL))        /* wait for the thread 2 to finish */
    {
      printf("\n ERROR joining thread");
      exit(1);
    }


Thanks in advance!
Oh there is the confusion =)

pthread_join is not there to "start" threads.
pthread_join - wait for thread termination


Thread1 and Thread2 are already started when they were "created".

If you were to remove the pthread_join statements, your main Thread would
do this stuff:

1
2
3
4
5
    
if (count < 2 * NITER) 
printf("\n BOOM! count is [%d], should be %d\n", count, 2*NITER);
else
printf("\n OK! count is [%d]\n", count);


probably before thread1 or thread2 have finished
(which could result in a run-time error when you don't have a Mutex
around the above code, because also "main Thread" is just another Thread
and thread1 and thread2 are using count. Which means "main Thread"s access to count at the same time might as well result in a problem again)

What will happen if you're lucky not to run into a run-time error (which would mean some angel used its magic power to make you really lucky that none of the other threads happens to use count in the moment "main thread" uses it (which is unlikely)) , you probably get a wrong result when printing count since thread1 and thread2 are still mid-calculation and you get a result < "right result".


yo early in the morning I hope I made it clear ^.^


@Glandy
Thanks again for taking time to answer this.

I have one more question......:) No.. I am kidding....its very clear to me

I was thinking earlier that if we use pthread_join then main thread gives control to that thread and pauses till that thread is completely executed
if (count < 2 * NITER)
printf("\n BOOM! count is [%d], should be %d\n", count, 2*NITER);
else
printf("\n OK! count is [%d]\n", count);

why main thread cant execute above code while its waiting for other two threads?

I assumed that when we do pthread_join then main thread will execute all the statements inside it while waiting for joined threads.

I dont understand why main has to stop just before the above statements?

If I create one more thread say thread3 and join this thread before the above code then will thread3 resume itself after thread1 and thread2 have finished? If main thread launches thread3 also while waiting for thread1 and thread2 then why it had to stop executing above code?


Thanks in advance
I hope I am making sense.
Why main thread had to stop executing above code till thread1 and thread2 are finished ..It could have executed above code like it did with two previous join statements.

Please help
if(pthread_join(tid1, NULL)) /* wait for the thread 1 to finish */

You already have it there as a comment right next to it ^.^

When your main Thread reaches this line (the "thread_join") then it waits right there until the thread (in this case tid1) finished whatever it's doing and only then resumes.
Then it goes on in your code and waits for thread2 to finish as well (which could already have finished before thread1 did, remember they are both running when u reach the first "join"). Then "main Thread" would just see: hey "thread_join (second one)" .. yap has finished let's print count.

I think I repeat myself ^.^
There's probably a more detailed explanation (probably even better) somewhere in the web just waiting to be read ;)
1
2
if(pthread_join(tid1, NULL)) /* wait for the thread 1 to finish */
 


@Glandy

This is last doubt,I promise :)


When main thread stops at this statement it has to wait for thread1 to finish.

Now lets say thread 2 is not finished yet when mainthread reaches above statement ....then does main thread let already running thread2 execute while it is waiting for thread1 to finish?


Thanks in advance.
Here before main thread reaches first join statement thread1 and thread2 are running simeltaneously.

if(pthread_join(tid1, NULL))
But when main thread reaches first join statement,then only thread1 will be running,so do we not have any problems related to a simeltaneous access as only one thread is running?

I am curious to know what will happen to thread2 while main thread is waiting for thread1 to finish at first join statement.


Thanks in advance
you have three threads: main, thread1, thread2

if one of them is in a waiting state the other threads are doing their job

By the way: starting a thread is an expensive operation. That means that thread1 could be finished before thread2 starts its execution. Especially when one thread is rather busy
Topic archived. No new replies allowed.