0

I want to print the passed to create_thread argument. I create an array with 10 int's to simulate the number of each thread -

void* thr_func(void *arg){

printf("\nTHREAD ID %d", *(int*)arg);
return 0;

}


int main(){
int arr[10]={0,1,2,3,4,5,6,7,8,9};

pthread_t thread_id;
for(int i=0;i<10;i++){

pthread_create(&thread_id, NULL, &thr_func,&arr[i]);
}
return 0;

}

Here is the output from two runs 1:

THREAD ID 1
THREAD ID 5
THREAD ID 6
THREAD ID 2
THREAD ID 3
THREAD ID 4
TTHREAD ID 0
THREAD ID 3

2:

THREAD ID 1
THREAD ID 2
THREAD ID 5
THREAD ID 6
THREAD ID 3
THREAD ID 7
THREAD ID 4
THREAD ID 8
THREAD ID 8

I know I can't rely on consecutive numbers, but why does it print some of them twice ?

loannnlo
  • 111
  • 1
  • 6
  • Buffering issues? Also note that output to `stdout` is by default *line-buffered*, meaning the output buffer will be flushed on a newline. That's why you should always put newlines *last* in your output. – Some programmer dude Jul 31 '18 at 12:06
  • 1
    Also note that your process might exit before all threads have started running, or before they are finished. That will kill all threads. – Some programmer dude Jul 31 '18 at 12:07
  • If I put sleep for one second, all 10 numbers are printed, but without sleep and newlines in the end, still some are printed twice – loannnlo Jul 31 '18 at 12:12
  • 1
    @Someprogrammerdude I think waiting on the child threads for their termination should work (`pthread_join`)? – Alan Jul 31 '18 at 12:16
  • Then it's most likely a buffering issues when the process ends. Perhaps something like this: In your example the thread 8 have filled the buffer and it have been printed, but then the process ends before the buffer is cleared, and when the process ends the buffer is flushed (and printed!) so you see that line again. – Some programmer dude Jul 31 '18 at 12:16
  • @Alan Yes, waiting for the threads (in a second loop) is definitely the right thing to do. Always (unless detaching the threads of course, but then the process should still not plain end). – Some programmer dude Jul 31 '18 at 12:17
  • @Someprogrammerdude so that should be the answer to the `OP's` question tho. – Alan Jul 31 '18 at 12:18
  • @FelixPalmen creating array of pthread_t and passing a different one each time works! I definitely dont understand why – loannnlo Jul 31 '18 at 12:19
  • @loannnlo I didn't find any evidence so far, therefore deleted this comment. But I'm not sure what a `pthreads` implementation is allowed to put inside a `pthread_t`. If the argument pointer might be stored there, that would be a simple explanation. –  Jul 31 '18 at 12:20
  • @loannnlo anyways, you'll need all those `pthread_t`s for properly joining the threads when they finished. –  Jul 31 '18 at 12:23
  • @loannnlo The "duplicate output" is a bug in glibc (see the linked duplicate). Simple fix is to call `pthread_exit(0);` at the end of main so that only main thread exits. This way you wouldn't need `pthread_join` or have to store pthread_t ids. – P.P Jul 31 '18 at 12:55

1 Answers1

1

As @Some programmer dude mentioned, you should always wait for the termination of your single child threads in your main function (except you detach your threads). The reason why some of your arrayelements are printed twice or more often is because before your buffer is cleared the thread may gets killed. (In your case the thread 8). To avoid that the processes are shut-down before they have finished their work you have to waitfor your threads, or in other words you have to join your threads.

That is done by adding the function: pthread_join(pthread_t thread, void **retvalue);

The pthread_join() function waits for the thread specified by thread to terminate.

Just put it in a separate loopafter your pthread_create() function and the parent thread (main) will wait for his childs.

Edit:
To wait for each thread you could change your pthread_tvariable to an array of threads: pthread_t thread[10] so you could wait for each thread in relation to the index.

int arr[10]={0,1,2,3,4,5,6,7,8,9};
pthread_t thread[10];

for(int i=0;i<10;i++){
    pthread_create(&thread[i], NULL, &thr_func,&arr[i]);
}

for(int i=0;i<10;i++){
    pthread_join(thread[i],NULL);
}
Alan
  • 589
  • 5
  • 29
  • Also it's worth to mention that each thread must have it own `pthread_t` variable. – Support Ukraine Jul 31 '18 at 12:37
  • @4386427 that was my **guess** as well, but can you provide some evidence for that? –  Jul 31 '18 at 12:39
  • @FelixPalmen Well evidence... hmmm, I don't know but the variable hold the information for identifying the individual thread. So overwriting the value when creating the next thread will make you loose the handle to the thread. – Support Ukraine Jul 31 '18 at 12:40
  • @4386427 sure, but that alone isn't enough for a **must** -- or do you mean "*in order to use `pthread_join()`*"? –  Jul 31 '18 at 12:41
  • @FelixPalmen Not sure if this quote from a man page is sufficient as evidence: "Before returning, a successful call to pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the thread in subsequent calls to other pthreads functions." – Support Ukraine Jul 31 '18 at 12:41
  • The simpliest solution would be to create a `pthread` array and wait for each thread in relation to the index. – Alan Jul 31 '18 at 12:41
  • @FelixPalmen yes. `pthread_join` is one function that requires the variable but there are other pthread functions than join that requires it. To me overwriting the pthread_t variable for a running thread is similar to overwriting a pointer to dynamic allocated memory or a file pointer. – Support Ukraine Jul 31 '18 at 12:45
  • @4386427 I understand your point, but both of them aren't forbidden. OP said the duplicates went away by not reusing the `pthread_t`s. A simple explanation would be the threading library stores the argument pointer there, creating a race condition when the thread isn't scheduled immediately. This would be an error if it isn't explicitly forbidden to reuse a `pthread_t` of a running thread. –  Jul 31 '18 at 13:01
  • @FelixPalmen my answer is right? should solve OP's question. Doesn't it? – Alan Jul 31 '18 at 13:04
  • 1
    @FelixPalmen The problem does **not** go away simply by not reusing `pthread_t`. The `pthread_join` is also required. – Support Ukraine Jul 31 '18 at 13:09
  • @4386427 yes so why doesn`t my answer get upvoted? Is there anything which is not correct? – Alan Jul 31 '18 at 13:13
  • @alan I'm not sure about the correctness of the explanation in the start of your answer. Therefore I can't vote. But the last part (i.e. under the edit) do seem correct to me. – Support Ukraine Jul 31 '18 at 13:15
  • @4386427 I think it should be upvoted tho. but yes no problem. :), I am here to help not for the rep. – Alan Jul 31 '18 at 13:16
  • @4386427 see [this comment](https://stackoverflow.com/questions/51612987/print-passed-argument-to-pthread-create?noredirect=1#comment90191468_51612987), it suggests otherwise. –  Jul 31 '18 at 13:59
  • @FelixPalmen I did read that comment. Maybe the timing of OPs system made it work for OP but on my system it also fails with an array of pthread_t In other words the `join` is required. – Support Ukraine Jul 31 '18 at 14:02
  • It would be interesting to check the code to see if there is a null check on the threadId pointer. It's not uncommon for pointer arguments to be ignored if set to null, eg. if a threadId is not required. The available documentation does not say there is, nor that there is not, (so, of course, you have to assume there is not). In many cases, there would be a big design problem if the lifetime of the the threadId store had to be the same as the thread, especially if detaching a new thread somewhere in a library/subsystem - it would be a really nasty contraint. – Martin James Jul 31 '18 at 14:15
  • 1
    'you have to waitfor your threads, or in other words you have to join your threads' - or ensure that their work is complete in some other manner. – Martin James Jul 31 '18 at 14:20