Good afternoon, the problem is to build a multi-threaded computation and specifically that the necessary parameter i needs to be passed to each stream from an array of threads of dimension n at each iteration of k ;

//n = чему - то; int k; for(k= 0; k< K; k++) { pthread_t threads[n]; double* res[n]; int i; for(i=0; i<n; i++) { struct info inft = {.parameter = i, .result = &res[i]}; // составление структуры для треда pthread_create( &threads[i], NULL, calculate, (void*)&inft ); } //ожидание закрытия треда и суммируем полученный резалт double result = 0; for(i=0; i<n; i++) { pthread_join( threads[i], NULL); result += res[i]; } } 

the thread function looks like this:

 void* calculate (void* args) { struct info myinf = (struct info)&args; int i_current = myinf->parameter; printf("start with %d", i_current); double result = 0; result = somefunc(myinf->result, i_current);// что то делаем *(myinf->result)= result; printf("finish with %f", result); } 

I expected that each stream will be given its own i and for each stream there will be a different result. But in the end, at each iteration, i - in the streams the same values

k = 1, n = 3 start with 2 finish with 66666 start with 2 start with 2 finish with 66666 finish with 66666

I tried a lot (locks, sending by reference, etc.) but it does not work as it should. Are there any ideas?

    3 answers 3

    You are actually passing a pointer to a local variable. Upon exiting the loop, it generally disappears as such, so that the address is sent to the streams to nowhere. You still allocate memory for each stream:

      pthread_t threads[n]; double* res[n]; 

    Well, allocate immediately the memory for the transferred structures (by the way, if you create them, then you will not need to transfer the address to store the result - store it directly in the structure ...). In this case, everything will be correct - your streams should be completed even before leaving the block, so that the lifetime of the structures will exceed the lifetime of the streams.

    Only here ... double*res[n] - you have an array of pointers to double . Uninitialized. Those. in the structure, you pass the address where the pointer to the double is stored. Pointer uninitialized. By which you write something. And then, on exit, you begin to summarize the pointers . Is this the exact functionality you need? ...

      When you call pthread_create, the structure is the same, just lying on the stack and the address of the same memory area is given to all threads. It is necessary to explicitly allocate memory for the structures transmitted inside the stream, through malloc (or new), to fill and transfer.

       struct info *inft = (struct info *)malloc(sizeof(struct info)); inft->parameter=i; ... pthread_create( &threads[i], NULL, calculate, (void*)inft ); 

      Only you need to remember at the completion of threads to perform free for these areas of memory.

      • and how to determine the required amount of memory? for malloc - gebond
      • @gebond you select the structure, and take its size. As I wrote in the example sizeof(struct info) - Mike
      • Yes, there is no need to suffer with malloc for such trifles. I would generally create a struct tinfo { pthread_t thread; int parametr; double res; } inft[n]; struct tinfo { pthread_t thread; int parametr; double res; } inft[n]; and did not suffer. Next in the cycle we write the parameter, save the stream, and the output and the result in the structure lie. All in one place, no malloc/free with the danger of forgetting something and getting a leak ... - Harry

      The problem is that you pass a pointer to a stack variable to threads, whose address is the same. In fact, this variable is created every time it enters the loop body where you start the streams, and is deleted when you exit it. The transmitted address becomes invalid, but you still continue to work with it from streams.

      The solution is to have a separate structure for each thread with which other threads do not work.

       int k; for(k= 0; k< K; k++) { pthread_t threads[n]; struct info inft[n]; int i; for(i=0; i<n; i++) { inft[i].parameter = i; inft[i].result = 0; // теперь info.result должен быть не // указателем, а просто int pthread_create( &threads[i], NULL, calculate, (void*)&inft[i]); } // ... }