I've got a simple C program that uses mutex's to collect a char from the standard input on one thread and print it out on another thread. Both threads start correctly (the printf in the below saying that the thread started runs), but then neither of the while's get run since I introduced Mutex'. Does anyone have an idea as to why? (I collect two chars in my char array as I am collecting the return char as well.)
Thanks!
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id;/* ID returned by pthread_create() */
char passedChar[2];
pthread_mutex_t passedCharMutex;
pthread_cond_t conditionalSignal;
};
static void *thread_1_start(void *arg) {
struct thread_info *myInfo = arg;
printf("Started thread id: %d\n", myInfo->thread_id);
while (1) {
printf("thread1 while ran");
pthread_mutex_lock(&myInfo->passedCharMutex);
int rid = read(0,myInfo->passedChar,2);
pthread_mutex_unlock(&myInfo->passedCharMutex);
}
pthread_exit(0);
}
int main() {
struct thread_info tinfo;
printf("Main thread id: %d\n", tinfo.thread_id);
int s = pthread_create(&tinfo.thread_id,
NULL, // was address of attr, error as this was not initialised.
&thread_1_start,
&tinfo);
pthread_join(tinfo.thread_id,NULL);
while (1) {
printf("thread2 while ran");
pthread_mutex_lock(&tinfo.passedCharMutex);
write(1,tinfo.passedChar,2);
pthread_mutex_unlock(&tinfo.passedCharMutex);
}
}
pthread_mutex_t and pthread_cond_t must be intitialized before you can use them.
struct thread_info tinfo;
pthread_mutex_init(&tinfo.passedCharMutex, NULL);
pthread_cond_init(&tinfo.conditionalSignal, NULL);
In this case you could initialize them when initializing the tinfo variable too:
struct thread_info tinfo = {
.passedCharMutex = PTHREAD_MUTEX_INITIALIZER,
.conditionalSignal = PTHREAD_COND_INITIALIZER
};
You also have a
pthread_join(tinfo.thread_id,NULL);
after you create your first thread, that will cause you wait until your thread ends, which it never does since thread_1_start() runs an infinite loop - you'll never reach the while loop in main().
While not part of your question, there's additional problems:
There's no synchronization of the logic of your two threads. As it currently stands, they both run without any regard to eachother, so your main() might print out passedChar many times before your thread_1_start() reads anything.
Likewise, thread_1_start() might read a lot of data before your main() thread have a chance to print it.
What you probably want is:
Thread A: read 2 chars
Thread A: signal Thread B that there is 2 chars to process
Thread A: wait until Thread B has processed the 2 chars.
Thread B: wait for thread A to signal that there's 2 chars to process
Thread B: process the 2 chars
Thread B: signal Thread A that we're done process
When thread 1 comes to this line,
int rid = read(0,myInfo->passedChar,2);
it holds the lock and then blocks for input. Tread 2 waits for the thread 1 to exit. And if no input ever comes neither thread will make progress.
Related
I'm doing a C application that reads and parses data from a set of sensors and, according to the readings of the senors, it turns on or off actuators.
For my application I will be using two threads, one to read and parse the data from the sensors and another one to act on the actuators. Obviously we may face the problem of one thread reading data from a certain variable while another one is trying to write on it. This is a sample code.
#include <pthread.h>
int sensor_values;
void* reads_from_sensor(){
//writes on sensor_values, while(1) loop
}
void* turns_on_or_off(){
//reads from sensor_values, while(1) loop
}
int main(){
pthread_t threads[2];
pthread_create(&threads[1],NULL,reads_from_sensor,NULL);
pthread_create(&threads[2],NULL,turns_on_or_off,NULL);
//code continues after
}
My question is how I can solve this issue, of a certain thread writing on a certain global variable while other thread is trying to read from it, at the same time. Thanks in advance.
OP wrote in the comments
The project is still in an alpha stage. I'll make sure I optimize it once it is done. #Pablo, the shared variable is sensor_values. reads_from_sensors write on it and turns_on_or_off reads from it.
...
sensor_value would be a float as it stores a value measured by a certain sensor. That value can either be voltage, temperature or humidity
In that case I'd use conditional variables using pthread_cond_wait and
pthread_cond_signal. With these functions you can synchronize threads
with each other.
The idea is that both threads get a pointer to a mutx, the condition variable
and the shared resource, whether you declared them a global or you pass them as
thread arguments, doesn't change the idea. In the code below I'm passing all
of these as thread arguments, because I don't like global variables.
The reading thread would lock the mutex and when it reads a new value of the
sensor, it writes the new value in the shared resource. Then it call
pthread_cond_signal to send a signal to the turning thread that a new value
arrived and that it can read from it.
The turning thread would also lock the mutex and execute pthread_cond_wait to
wait on the signal. The locking must be done in that way, because
pthread_cond_wait will release the lock and make the thread block until the
signal is sent:
man pthread_cond_wait
DESCRIPTION
The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. The application shall ensure that
these functions are called with mutex locked by the calling thread; otherwise, an error (for PTHREAD_MUTEX_ERRORCHECK and robust
mutexes) or undefined behavior (for other mutexes) results.
These functions atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means
atomically with respect to access by another thread to the mutex and then the condition variable. That is, if another thread is
able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or
pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.
Example:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct thdata {
pthread_mutex_t *mutex;
pthread_cond_t *cond;
int *run;
float *sensor_value; // the shared resource
};
void *reads_from_sensors(void *tdata)
{
struct thdata *data = tdata;
int i = 0;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
// read from sensor
*data->sensor_value = (rand() % 2000 - 1000) / 10.0;
// just for testing, send a singnal only every
// 3 reads
if((++i % 3) == 0)
{
printf("read: value == %f, sending signal\n", *data->sensor_value);
pthread_cond_signal(data->cond);
}
pthread_mutex_unlock(data->mutex);
sleep(1);
}
// sending signal so that other thread can
// exit
pthread_mutex_lock(data->mutex);
pthread_cond_signal(data->cond);
pthread_mutex_unlock(data->mutex);
puts("read: bye");
pthread_exit(NULL);
}
void *turns_on_or_off (void *tdata)
{
struct thdata *data = tdata;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
pthread_cond_wait(data->cond, data->mutex);
printf("turns: value read: %f\n\n", *data->sensor_value);
pthread_mutex_unlock(data->mutex);
usleep(1000);
}
puts("turns: bye");
pthread_exit(NULL);
}
int main(void)
{
srand(time(NULL));
struct thdata thd[2];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// controlling vars
int run_rfs = 1;
int run_tof = 1;
float sensor_value;
thd[0].run = &run_rfs;
thd[1].run = &run_tof;
thd[0].mutex = &mutex;
thd[1].mutex = &mutex;
thd[0].cond = &cond;
thd[1].cond = &cond;
thd[0].sensor_value = &sensor_value;
thd[1].sensor_value = &sensor_value;
pthread_t th[2];
printf("Press ENTER to exit...\n");
pthread_create(th, NULL, reads_from_sensors, thd);
pthread_create(th + 1, NULL, turns_on_or_off, thd + 1);
getchar();
puts("Stopping threads...");
run_rfs = 0;
run_tof = 0;
pthread_join(th[0], NULL);
pthread_join(th[1], NULL);
return 0;
}
Output:
$ ./a
Press ENTER to exit...
read: value == -99.500000, sending signal
turns: value read: -99.500000
read: value == -25.200001, sending signal
turns: value read: -25.200001
read: value == 53.799999, sending signal
turns: value read: 53.799999
read: value == 20.400000, sending signal
turns: value read: 20.400000
Stopping threads...
read: bye
turns: value read: 20.400000
turns: bye
Note that in the example I only send the signal every 3 seconds (and do a long
sleep(1)) for testing purposes, otherwise the terminal would overflow immediately
and you would have a hard time reading the output.
See also: understanding of pthread_cond_wait() and pthread_cond_signal()
Your question is too generic. There are different multithread synchronization methods mutex, reader-writer locks, conditional variables and so on.
The easiest and most simple are mutex (mutual excluasion). They are pthread_mutex_t type variables. You first need to initialize them; you can do it in two ways:
assigning to the mutex variable the constant value PTHREAD_MUTEX_INITIALIZER
calling the funtion pthread_mutex_init
Then before reading or writing a shared variable you call the function int pthread_mutex_lock(pthread_mutex_t *mutex); and after exited the critical section you must release the critical section by calling int pthread_mutex_unlock(pthread_mutex_t *mutex);.
If the resource is busy the lock will block the execution of your code until it gets released. If you want to avoid that take a look at int pthread_mutex_trylock(pthread_mutex_t *mutex);.
If your program has much more reads than writes on the same shared variable, take a look at the Reader-Writer locks.
Firstly, I'm Italian and sorry for my bad English.
Anyway, I should do this exercise:
"Write in C a programm which generate a thread. The main shows odd number from 1 to 9, the thread shows even number from 2 to 10. Synchronize the main and the thread with semaphores"
I have written the pseudocode in this way:
//semaphores
semParent = free
semChild = busy
main
generate thread "child"
for i=1 to 9 step 2
P(semParent)
print i
V(semChild)
end for
end main
child
for i=2 to 10 step 2
P(semChild)
print i
V(semParent)
end child
And this is how I have implemented in C:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t semParent;
pthread_mutex_t semChild = PTHREAD_MUTEX_INITIALIZER;
void* functionChild (void* arg) {
for(int i=2; i<=10; i+=2) {
pthread_mutex_lock(&semChild);
printf("CHILD: %d\n",i);
pthread_mutex_unlock(&semParent);
}
return NULL;
}
int main(void) {
pthread_t child;
pthread_create(&child, NULL, &functionChild, NULL);
pthread_mutex_init(&semParent, NULL);
for(int i=1; i<=9; i+=2) {
pthread_mutex_lock(&semParent);
printf("PARENT : %d\n",i);
pthread_mutex_unlock(&semChild);
}
pthread_join(child, NULL);
}
But the output is always different whenever I run the program.
What's wrong?
I use CygWin64 Terminal in Windows 10 64 bit.
Thanks in advance.
A pthread_mutex_t is not a semaphore (though a semaphore can be used as a mutex if you do a "V" to initialize it to "free"). The semaphore API is sem_init, sem_post and sem_wait.
By using pthread_mutex_unlock on a mutex that was locked by another thread, your program is triggering undefined behavior.
This may not be the cause of the problem you are experiencing now, but you should never use printf() in a multithreaded program. printf() writes to a buffer and doesn't always print to the screen right away. Instead you should use sprintf() and write:
char buff[20];
sprintf("PARENT: %d\n", i);
write(1, buff, strlen(buff));
I think that pthread_mutex_init(&semParent, NULL) with NULL attributes and PTHREAD_MUTEX_INITIALIZER have the same effect, which is both locks are initialised to unlocked. Your problem though does not have a critical section with the strict meaning. So a better solution whould be condition variables as #Serhio mentioned. You can also check out semaphores http://www.csc.villanova.edu/~mdamian/threads/posixsem.html which give bigger freedom and can also have the functionality of mutexes.
I am trying to write a code that does not block main() when pthread_join() is called:
i.e. basically trying to implement my previous question mentioned below:
https://stackoverflow.com/questions/24509500/pthread-join-and-main-blocking-multithreading
And the corresponding explanation at:
pthreads - Join on group of threads, wait for one to exit
As per suggested answer:
You'd need to create your own version of it - e.g. an array of flags (one flag per thread) protected by a mutex and a condition variable; where just before "pthread_exit()" each thread acquires the mutex, sets its flag, then does "pthread_cond_signal()". The main thread waits for the signal, then checks the array of flags to determine which thread/s to join (there may be more than one thread to join by then).
I have tried as below:
My status array which keeps a track of which threads have finished:
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
The thread routine, it sets the corresponding array element when the thread finishes and also signals the condition variable:
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
I am not able to write the corresponding parts pthread_join() and pthread_cond_wait() functions. There are a few things which I am not able to implement.
1) How to write corresponding part pthread_cond_wait() in my main()?
2) I am trying to write it as:
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
But it does not enter the while loop.
3) How to use pthread_join() so that I can get the return value stored in my arg[i].returnStatus
i.e. where to put below statement in my main:
`pthread_join(T[i],&(arg[i].returnStatus));`
COMPLETE CODE
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#define THREAD_NUM 5
#define FALSE 0
#define TRUE 1
void waitFor (unsigned int secs) {
time_t retTime;
retTime = time(0) + secs; // Get finishing time.
while (time(0) < retTime); // Loop until it arrives.
}
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
typedef struct {
int id;
void* returnStatus;
}THREAD_ARGUMENT;
THREAD_FINISH_STATE ThreadFinishStatus;
void initializeState(THREAD_FINISH_STATE* state)
{
int i=0;
state->signalled=FALSE;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_init(&(state->mutex),NULL);
pthread_cond_init(&(state->FINISHED),NULL);
}
void destroyState(THREAD_FINISH_STATE* state)
{
int i=0;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_destroy(&(state->mutex));
pthread_cond_destroy(&(state->FINISHED));
}
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
int main()
{
THREAD_ARGUMENT arg[THREAD_NUM];
pthread_t T[THREAD_NUM];
int i=0;
initializeState(&ThreadFinishStatus);
for(i=0;i<THREAD_NUM;i++)
{
arg[i].id=i;
}
for(i=0;i<THREAD_NUM;i++)
{
pthread_create(&T[i],NULL,THREAD_ROUTINE,(void*)&arg[i]);
}
/*
Join only if signal received
*/
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
//Wait
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
destroyState(&ThreadFinishStatus);
return 0;
}
Here is an example of a program that uses a counting semaphore to watch as threads finish, find out which thread it was, and review some result data from that thread. This program is efficient with locks - waiters are not spuriously woken up (notice how the threads only post to the semaphore after they've released the mutex protecting shared state).
This design allows the main program to process the result from some thread's computation immediately after the thread completes, and does not require the main wait for all threads to complete. This would be especially helpful if the running time of each thread varied by a significant amount.
Most importantly, this program does not deadlock nor race.
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <queue>
void* ThreadEntry(void* args );
typedef struct {
int threadId;
pthread_t thread;
int threadResult;
} ThreadState;
sem_t completionSema;
pthread_mutex_t resultMutex;
std::queue<int> threadCompletions;
ThreadState* threadInfos;
int main() {
int numThreads = 10;
int* threadResults;
void* threadResult;
int doneThreadId;
sem_init( &completionSema, 0, 0 );
pthread_mutex_init( &resultMutex, 0 );
threadInfos = new ThreadState[numThreads];
for ( int i = 0; i < numThreads; i++ ) {
threadInfos[i].threadId = i;
pthread_create( &threadInfos[i].thread, NULL, &ThreadEntry, &threadInfos[i].threadId );
}
for ( int i = 0; i < numThreads; i++ ) {
// Wait for any one thread to complete; ie, wait for someone
// to queue to the threadCompletions queue.
sem_wait( &completionSema );
// Find out what was queued; queue is accessed from multiple threads,
// so protect with a vanilla mutex.
pthread_mutex_lock(&resultMutex);
doneThreadId = threadCompletions.front();
threadCompletions.pop();
pthread_mutex_unlock(&resultMutex);
// Announce which thread ID we saw finish
printf(
"Main saw TID %d finish\n\tThe thread's result was %d\n",
doneThreadId,
threadInfos[doneThreadId].threadResult
);
// pthread_join to clean up the thread.
pthread_join( threadInfos[doneThreadId].thread, &threadResult );
}
delete threadInfos;
pthread_mutex_destroy( &resultMutex );
sem_destroy( &completionSema );
}
void* ThreadEntry(void* args ) {
int threadId = *((int*)args);
printf("hello from thread %d\n", threadId );
// This can safely be accessed since each thread has its own space
// and array derefs are thread safe.
threadInfos[threadId].threadResult = rand() % 1000;
pthread_mutex_lock( &resultMutex );
threadCompletions.push( threadId );
pthread_mutex_unlock( &resultMutex );
sem_post( &completionSema );
return 0;
}
Pthread conditions don't have "memory"; pthread_cond_wait doesn't return if pthread_cond_signal is called before pthread_cond_wait, which is why it's important to check the predicate before calling pthread_cond_wait, and not call it if it's true. But that means the action, in this case "check which thread to join" should only depend on the predicate, not on whether pthread_cond_wait is called.
Also, you might want to make the while loop actually wait for all the threads to terminate, which you aren't doing now.
(Also, I think the other answer about "signalled==FALSE" being harmless is wrong, it's not harmless, because there's a pthread_cond_wait, and when that returns, signalled would have changed to true.)
So if I wanted to write a program that waited for all threads to terminate this way, it would look more like
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
// AllThreadsFinished would check that all of Finish_Status[] is true
// or something, or simpler, count the number of joins completed
while (!AllThreadsFinished()) {
// Wait, keeping in mind that the condition might already have been
// signalled, in which case it's too late to call pthread_cond_wait,
// but also keeping in mind that pthread_cond_wait can return spuriously,
// thus using a while loop
while (!ThreadFinishStatus.signalled) {
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
}
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled=FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
Your code is racy.
Suppose you start a thread and it finishes before you grab the mutex in main(). Your while loop will never run because signalled was already set to TRUE by the exiting thread.
I will echo #antiduh's suggestion to use a semaphore that counts the number of dead-but-not-joined threads. You then loop up to the number of threads spawned waiting on the semaphore. I'd point out that the POSIX sem_t is not like a pthread_mutex in that sem_wait can return EINTR.
Your code appears fine. You have one minor buglet:
ThreadFinishStatus.signalled==FALSE; //Reset signalled
This does nothing. It tests whether signalled is FALSE and throws away the result. That's harmless though since there's nothing you need to do. (You never want to set signalled to FALSE because that loses the fact that it was signalled. There is never any reason to unsignal it -- if a thread finished, then it's finished forever.)
Not entering the while loop means signalled is TRUE. That means the thread already set it, in which case there is no need to enter the loop because there's nothing to wait for. So that's fine.
Also:
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
There's no need to test the thing you just set. It's not like the set can fail.
FWIW, I would suggest re-architecting. If the existing functions like pthread_join don't do exactly what you want, just don't use them. If you're going to have structures that track what work is done, then totally separate that from thread termination. Since you will already know what work is done, what different does it make when and how threads terminate? Don't think of this as "I need a special way to know when a thread terminates" and instead think of this "I need to know what work is done so I can do other things".
I am using pthread_t to print out the pid of a thread that I manually create in C. However, I print it before I create my new thread (passing it by ref as a parameter) and it prints a different value (presumably the thread that my main function is executing on). I would have expected it to default to be 0 or unitialised. Any ideas?
Thanks,
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
struct thread_info { /* Used as argument to thread_start() */
pthread_t thread_id;/* ID returned by pthread_create() */
};
static void *thread_1_start(void *arg) {
struct thread_info *myInfo = arg;
printf("Started thread id: %d\n", myInfo->thread_id);
pthread_exit(0);
}
int main() {
struct thread_info tinfo;
int s;
printf("Main thread id: %d\n", tinfo.thread_id);
s = pthread_create(&tinfo.thread_id,
NULL, // was address of attr, error as this was not initialised.
&thread_1_start,
&tinfo);
pthread_join(tinfo.thread_id,NULL);
}
Actual output:
Main thread id: 244580352
Started thread id: 245325824
Expected output:
Main thread id: // 0 or undefined
Started thread id: 245325824
The problem is you are not initialising tinfo structure.
In local variables (as opposed to global/heap variables), values are not initialised in C Programming Language.
So, if you do something like:
int c;
printf("%d", c);
You should not expect a coherent value since it will depend on what's on that memory location in that moment.
You need to initialize tinfo variable. Using memset or assigning tinfo.thread_id = 0 explicitly.
There is no thread-specific logic to initialize tinfo; it is just a regular C struct. It will have whatever data was in that memory address at the initialization. You need to explicitly initialize it.
You can initialize the value to zero by:
struct thread_info tinfo = { 0 };
Declare struct thread_info tinfo; global and see what happens.
There's a number of important things you need to know.
First, pthread_t is opaque. You can't reliably print it with printf because nowhere in the POSIX standard is pthread_t specified as beinban into, struct or whatever. By definition you can't print it and get a meaningful output.
Second, if a thread needs to know it's pthread_t ID it can call pthread_self(). You don't need to tell the thread what its ID is externally like you're trying to do.
But never mind that! The condition you describe where the printed output is close to what you're expecting is because you have a race between the thread printing out and pthread_create assigning the pthread_t to thread_info.thread_id, and due to pthread_t actually being an integer type on Linux (so it's likely that they're allocated sequentially, and you're just getting an old value).
This question already has answers here:
Wrong thread IDs in a multithreaded C program?
(2 answers)
Closed 8 years ago.
I compiled this code and the 99th threads that it's been created keeps creating more than one thread of number 99. Instead if i insert values from 1-10 or something small then the results are quite normal.
Here is the code.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
pthread_attr_t attr;
void* test(void *a)
{
int i=*((int *)a);
printf("The thread %d has started.\n",i);
pthread_mutex_lock(&m);
usleep(10000);
printf("The thread %d has finished.\n",i);
pthread_mutex_unlock(&m);
pthread_exit(NULL);
}
int main()
{
int i=0,j=0;
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
pthread_t thread[100];
for (i=0;i<100;i++)
{
j=i;
pthread_create(&thread[i],&attr,test,&j);
}
for (i=0;i<100;i++)
pthread_join(thread[i],NULL);
return 0;
}
i get:
..../*Normal Results*/
The thread 99 has finished.
The thread 99 has finished.
The thread 99 has finished.
The thread 99 has finished.
The thread 99 has finished.
The thread 99 has finished.
Why is this happening?
You need to keep all theadIds
int indexes[PTHREAD_COUNT];
for (i=0;i<100;i++) {
indexes[i] = i;
pthread_create(&thread[i], &attr, test, &indexes[i]);
}
Each thread is passed the same pointer to the same stack location (j) in your main thread. Without further synchronisation, its undefined when each thread will be scheduled and will run and access j before printing its value.
There are lots of ways you could print out a unique number from each thread, including
malloc a struct which includes (or is) this number in the main thread. Pass it to the child threads which are then responsible for freeing it
(Suggested by Brian Roche below) Declare an array of 100 ints, with values 0, 1, 2, etc. Pass the address of a different array item to each thread.
have each thread lock a mutex then copy/increment a global counter. The mutex could be passed into the thread or another global
pass a semaphore into each thread, signalling it once the number has been accessed. Wait on this semaphore in the main thread
Note that options 3 & 4 involve serialising startup of the threads. There's little point in running multiple threads if you do much of this!
i is the same address as j in your main code, and you sleep of 30 ms in the threads. So all threads have time to run until the first mutex call, then they all stop for (a little over) 30ms, and then print they have finished. Of course, i in the main loop is now 99, because you are finished with the pthread_join loop.
You need to have an array of "j" values [assuming you want all threads to run independently]. Or do something else. It all depends on what you are actually wanting to do.
you are passing the same memory location (&j) as the pointer to data a.
when threads start, they print out the value just assigned to j, which looks OK
But then only one get the lock and went to sleep, all others thus blocked. when the nightmare is over, memory location "a", of course, has a int value 99.