Click here to Skip to main content
15,886,518 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I am trying to start some threads in linux, for some reason I tried to test pthread before starting my project. in my test I have written a simple code that 2 thread starts in it and one of them increases a universal counter and other one decreases it, at the end the counter should be zero but some times it's -10,-7,10,6 and so. what's the problem? I think some times one of the threads fails or something. How can I make it right?
Thanks.

Code:
#include<iostream>
using namespace std;
#include<pthread.h>

int count=0;
void* func1(void *arg)
{
for(int i=0;i<10;i++)
   count++;
cout<<endl;
}

void* func2(void *arg)
{
for(int i=0;i<10;i++)
   count--;
cout<<endl;
}

int main()
{
pthread_t t1;
pthread_t t2;
for(int i=0;i<10;i++)
{
pthread_create(&t2,NULL,func2,NULL);
pthread_create(&t1,NULL,func1,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
cout<<count<<endl;
count=0;
}
return(0);
}
Posted

When you modify any kind of data from two or more different threads, then you have to protect the data with a lock. You can only modify the data when the current thread has successfully acquired the lock, then you have to release the lock after performing the write on the data. This way only one thread can write the data at a time. In your situation this disaster can happen:
1. Your counter is zero.
2. Both thread 1 and 2 read out this zero value at the same time to some register in the processor.
3. Thread 1 increases the value to one, and thread 2 decreses it to minus one.
4. Both threads write back their own value and one of them will win (random result, either -1 or 1).
With a lock you can achieve that while one of the threads is reading/modifying/writing the int, the other thread is blocking on the acquire method of the lock.
For simple integral values you can use gcc atomic builtins that will work well in your situation because they increment/decrement the integer values with locking: http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html[^]

I also recommend you to get some lessons on multithreading because with your current knowledge you will produce hell buggy multithreaded code and threading bugs are often hard to reproduce/find. Some threading bugs occur only once a month or so but then they can deadlock your program!
 
Share this answer
 
v2
Comments
mehdi_k 12-Sep-12 6:24am    
thank you for the answer, I'll try to read more about multithreading and locks, the reason I didn't use any lock was that I thought pthread_join forces a thread to finish up completely then the other one starts. do you think that this problem happens because I'm using 2 core CPU? because in this case both threads start processing at the same time.
pasztorpisti 12-Sep-12 7:01am    
Both threads start processing at the same time because you issue 2 pthread_create() calls and then you start waiting for one of those threads on your main thread. Anyway, it has no point to wait for the first thread and starting the second only after the first has finished because that is equivalent to doing the work of both threads on a single thread - possibly on the main thread without creating any threads. The bug I described can happen on both single/dual core processors. You can't and shouldn't avoid correct multithreading referring to single/multicore systems.
Chuck O'Toole 12-Sep-12 14:12pm    
In addition to this excellent answer and his response to your comment, let me add that while your C code (count++) looks like a single statement to you, it can be several executable statements in machine code, depending on the computer architecture. Plus, between any two of those machine instructions, one of your threads can be pre-empted by the kernel and the other thread scheduled and it can run to completion before your first thread gets another turn at the cpu. In fact, almost any scenario is possible. So you should *always* use proper data access synchronization techniques (semaphores, conditioned variables, etc) to properly protect any data "shared" among threads. This will prevent your program from being affected by the vagaries of the kernel and other things you have no control over. Learn this once and well and it will serve you forever.
pasztorpisti 12-Sep-12 14:24pm    
Nice clarification as an addition to 4 the steps in the answer. I would also add even some more info that came to my mind. Some architectures (like these days popular arm chipsets in mobile devices) have weak memory model (not strong model like x86 PCs). This means that if you write out something to memory on one of the cores of your processor then that write might wait in a write queue to be written out to physical shared memory before another core of the processor can see the change. Another problem with this is that even writes performed on the same core can go out to shared memory in different order. Proper synchronization makes sure that the write queue of the writing thread is flushed out (usually at the release lock) before the other thread can acquire the lock and read/write the shared data.
mehdi_k 12-Sep-12 16:20pm    
Thank you two for the response.
You are assuming that your threads will execute in a sequence .....
like Thread1 .... Thread2.....Thread1.....Thread2......and so on

But in case of multithreading , execution of thread is dependent on the OS schedular. Threads can execute in any manner. There is no guarantee that each thread will get equal amount of cpu time. Hence it is possible that one of thread might get more cpu time than other one.

Thumb rule is , do not build your program logic on the sequence of execution of threads.

If you have threads which are dependent on each other, you will need to use some kind of synchronization mechanism like mutex, signals. Use them cautiously.(They may cause deadlock if used carelessly)
 
Share this answer
 
Comments
mehdi_k 13-Sep-12 5:57am    
thank you for this good answer.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900