pthread with unique struct as parameter C - c

I have this piece of code that is giving me trouble.
I know all the threads are reading the same struct. But I have no idea how to fix this.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a,b;
} s_param;
void *
threadfunc(void *parm)
{
s_param *param2 = parm;
printf("ID:%d and v:%d\n",param2->a,param2->b);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
pthread_t thread[3];
int rc=0,i;
void * status;
for(i=0; i<3 ; ++i){
s_param param;
param.b=10;
param.a=i;
rc = pthread_create(&thread[i], NULL, threadfunc, &param ); // !!!!
if(rc){
exit(1);
}
}
for(i=0; i<3 ; ++i){
pthread_join(thread[i],&status);
}
return 0;
}
output:
ID:2 and v:10
ID:2 and v:10
ID:2 and v:10
and what I need:
ID:0 and v:10
ID:1 and v:10
ID:2 and v:10

The scope of the sparam in the for loop is static within that loop. When you set .a and .b you are writing to the same struct over and over, and all three threads are getting a pointer to that same single struct.
Instead, you could create three separate instances of the struct by making an array of them like so..
int main(int argc, char **argv)
{
pthread_t thread[3];
s_param param[3];
int rc=0,i;
void * status;
for(i=0; i<3 ; ++i){
param[i].b=10;
param[i].a=i;
rc = pthread_create(&thread[i], NULL, threadfunc, &param[i] ); // !!!!
if(rc){
exit(1);
}
}
... etc
Should mention that creating the structs (and the threads) in an array like this is only feasible since you clearly do a join() with the main thread. If you didn't do that join, you would be advised to either statically allocate the structs outside of the main function, or malloc them from the heap, because as soon as the entry thread exits the main function, the stack frame containing the array will become invalid and will soon be overwritten in an unpredictable way.

param lives on the same place in the stack during the execution of your main function. Every time you set new values, they're wiping out the old values, and all the threadfuncs are looking at the same spot in memory. malloc the structs, or otherwise create them from different memory locations. (Also, using stack memory for cross-thread data structures is worrisome; as soon as the function you're setting them up in exits, the memory is invalid.)

param is a local variable. It goes out of scope at the end of the loop's braces. You need to malloc a new s_param with each thread.
Or better, define a struct containing both a pthread_t and an s_param and use that type for thread[3].
typedef struct {
int a,b;
pthread_t t;
} s_param;
int main(int argc, char **argv)
{
s_param thread[3]; // declare threads + params together
int rc=0,i;
void * status;
for(i=0; i<3 ; ++i){
s_param *param = &thread[i]; // no persistent data declared here
param->b=10;
param->a=i;
rc = pthread_create(&thread[i].t, NULL, threadfunc, &thread[i] ); // !!!!
if(rc){
exit(1);
}
}
…

Related

Passing Struct Array to a Thread

I am trying to pass a whole array of a struct to a thread, where I need to have their index to differentiate the different arrays inside the thread.
typedef struct {
int x;
int y;
} StructA;
typedef struct {
StructaA str;
pthread_mutex_t* mutex;
} Parameters;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int n=3;
main(){
pthread_t thread;
StructA str[n];
Parameters thParam[n];
for (int i=0; i<n; i++){
thParam[i].str = &str[i];
thParam[i].mutex = &mutex;
}
for (int i=0; i<n; i++){
if(pthread_create(&thread[i], NULL, &Thread1, (void*)&thParam))
exit;
}
etc...
}
Thread1(params*){
Parameters * param[n];
StructA stra[n];
for (int i=0; i<n; i++){
??????????????????
}
}
I have thought about something like this:
for(int i=0; i<ghostN; i++){
param[i] = ((Parameters*) params+i);
stra[i] = param[i];
}
but I am just messing more and more the code. What would be the correct way to do this?
Consider that I must do this in order to see each str[n] values (the struct inside the main which I passed to the thread) inside the thread itself.
The memory of the main process is shared between all thereads. So, every thread has an ability to access the same variable or
arrays. The only thing which makes sense to pass to a thread startup function is somethign uniquie. Note, you cannot pass anything
to a thread, thread is not a function, but you can pass something to the thread start-up function to keep it on the stack of this
function. Every call to a function allocates stack unique to this function.
So, in your example I would keep the thParam array in the global scope to make it accessible by all threads, something like the following
Parameters thParam[n];
StructA str[n];
void *startThread(void *arg) {
long int i = (long int)arg;
use(thParam[i]);
}
main(){
pthread_t thread[n];
for (long int i=0; i<n; i++){
thParam[i].str = &str[i];
thParam[i].mutex = &mutex;
}
for (int i=0; i<n; i++){
if(pthread_create(&thread[i], NULL, &startThread, (void*)i))
exit;
}
...
}
Note that in the above case all writes to thParam is done before the thread starts. So there is no need to provide any
synchronization here. Also, since all threads access their own portion of the array only, defined by i, there is no need to
synchronize either.
You need to pass i by value, to avoid synchronization issues. Therefore you'd better have 'long int' to match its size to the size of the void* pointer.
And in your cases the thread must be an array as well.

How can I have a shared counter in multithreading using structs?

I'm pretty new with multithreading and I was trying to increment a shared counter whithout using global variables, my goal is try to maximize the concurrency among the different threads and increment the variable until a number I give in arguments... Sorry if is a lame question, but I would like a help here, when I compile my code and run it i get a segmentation fault... I think the error is in the variable count that I create and the shared counter!
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
typedef struct {
long *cnt; /* pointer to shared counter */
long n; /* no of times to increment */
int nr;
pthread_t id; /* application-specific thread-id */
} targ_t;
void *sfun(void *arg) {
targ_t *est = (targ_t *) arg;
here:
pthread_mutex_lock(&mutex);
(*(est->cnt))++;
pthread_mutex_unlock(&mutex);
if(*(est->cnt)<est->n)
goto here;
return NULL;
}
int main(int argc, char *argv[]){
targ_t real[3];
int c=0;
long count=0;
real[0].cnt=&count;
pthread_mutex_init(&mutex, NULL);
for(c=0;c<3;c++){
real[c].n=atoi(argv[1]);
real[c].nr=c+1;
pthread_create(&real[c].id,NULL,&sfun,&real[c]);
}
for(c=0;c<3;c++){
pthread_join(real[c].id,NULL);
}
pthread_mutex_destroy(&mutex);
printf("OVERALL %lu\n", count);
return 0;
}
TY in advance.
There are a number of problems identified in the comments:
Writing out loops with a label here: and a goto here; is not a particularly good idea. There are occasions (some, but not many, occasions) when it is appropriate to use goto — this is not one of those rare occasions.
You don't actually validate that your code was given an argv[1] to convert; could it be that you forgot to pass that argument?
However, your primary problem is that you initialize real[0].cnt but you do not initialize real[1].cnt or real[2].cnt, so those threads are accessing who knows what memory — it might be that they're using null pointers, or they might be pointers to anywhere in memory, allocated or not, aligned or not, writable or not.
You're also missing <stdlib.h>
You're testing *(est->cnt) outside the scope of mutual exclusion.
This code fixes those and some other issues:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
typedef struct
{
long *cnt; /* pointer to shared counter */
long n; /* no of times to increment */
int nr;
pthread_t id; /* application-specific thread-id */
} targ_t;
static void *sfun(void *arg)
{
targ_t *est = (targ_t *)arg;
while (1)
{
pthread_mutex_lock(&mutex);
long cval = *est->cnt;
if (cval < est->n)
++*est->cnt;
pthread_mutex_unlock(&mutex);
if (cval >= est->n)
break;
}
return NULL;
}
int main(int argc, char *argv[])
{
targ_t real[3];
long count = 0;
if (argc != 2)
{
fprintf(stderr, "Usage: %s count\n", argv[0]);
return(EXIT_FAILURE);
}
for (int c = 0; c < 3; c++)
{
real[c].cnt = &count;
real[c].n = atoi(argv[1]);
real[c].nr = c + 1;
if (pthread_create(&real[c].id, NULL, &sfun, &real[c]) != 0)
break;
}
for (int c = 0; c < 3; c++)
pthread_join(real[c].id, NULL);
pthread_mutex_destroy(&mutex);
printf("OVERALL %lu\n", count);
return 0;
}
When run (for example, the program is pth59):
$ pth59 100
OVERALL 100
$
Before moving the test (now on cval) so that the read of *est->cnt was done inside the scope of the mutex, I got an output OVERALL 102 from the same command line. It is important to access shared variables with proper mutual exclusion, even if it is read-only access.

segmentation fault in multithreading program

I'm trying to multiply two matrices using multithreading. But the code is giving segmentation fault. I am passing the row number and column number using a structure. The matrices a and b are made global. This is not entirely correct way to do it, but I'm just trying to understand how multithreading stuff works.
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int b[3][2]={{1,2},{3,4},{5,6}};
int c[3][2];
int k =3;
struct thread_data{
int m;
int n;
};
void* do_loop(void* threadarg)
{
int p,q;
struct thread_data *my_data;
my_data = (struct thread_data *) threadarg;
int i=my_data->m;
int j=my_data->n;
c[i][j]=0;
for(q=0;q<k;q++)
{
c[i][j]=c[i][j]+a[i][q]*b[q][j];
}
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
int i,j,k;
struct thread_data td[6];
int thr_id;
pthread_t p_thread[6];
int count=0;
for(i=0;i<3;i++)
for(j=0;j<2;j++)
{
td[count].m=i;
td[count].n=j;
thr_id = pthread_create(&p_thread[count], NULL, do_loop, (void*)&td[count]);
// pthread_join(p_thread[count],NULL);
count++;
}
return 0;
}
How can I fix the segmentation fault?
First thing, you need to wait for all the threads to finish (in main):
for (i = 0; i < count; ++i) {
pthread_join(p_thread[i],NULL);
}
Failure to do so will crash your app as the thread continue to work why the application is being destroyed.
You need to call pthread_join after you create all the threads.
If you create a thread and immediately call pthread_join you execution is serial as one thread is active at any given time.
Explanation:
"join" means: "wait for thread to finish execution". A thread finishes execution when either it returns from it's entry point function (function passed to pthread_create) or it calls pthread_exit.

Thread struct as function parameter C

I'm having a trouble passing a struct pointer into a function because I'm a bit confused with those pointers and references. I want to modify the thread.thread_num value from the thread_startfunction.
#include <stdio.h>
#include <stdlib.h> //malloc, free
#include <pthread.h>
#define N 5
// void *malloc(size_t);
struct thread {
pthread_t thread_id;
int thread_num;
// int thread_sum;
};
void *thread_start(void *thread)
{
struct thread *my_data;
my_data = (struct thread *)thread;
printf("num T: %i\n", my_data->thread_num);
my_data->thread_num=4;
printf("num T: %i\n", my_data->thread_num);
return NULL;
}
int main(int argc, char *argv[])
{
int i;
struct thread pthread_data;
struct thread *thread = &pthread_data;
thread->thread_num=2;
pthread_create(&thread->thread_id, NULL, thread_start, (void *)&thread);
printf("num: %i\n",thread->thread_num);
pthread_exit(NULL);
return 0;
}
But the value that print the main doesn't change (2).
And then I want to create an array of thread struct, but I don't know how exactly do that:
I guess it should be something like this:
int main(int argc, char *argv[])
{
int i;
struct thread pthread_data;
struct thread *thread[N-1] = &pthread_data; // I don't know how to manage this.
for(i=0; i<N; i++)
{
thread->thread_num=i;
pthread_create(&thread[i]->thread_id, NULL, thread_start, (void *)&thread[i]);
printf("num %i: %i\n",i,thread[i]->thread_num);
}
pthread_exit(NULL);
return 0;
}
Any thoughts?
I recommend you to read http://www.advancedlinuxprogramming.com/alp-folder/alp-ch04-threads.pdf
And here what you wanted:
#define N 5
typedef struct thread {
pthread_t thread_id;
int thread_num;
// int thread_sum;
} ThreadData;
void *thread_start(void *thread)
{
ThreadData *my_data = (ThreadData*)thread;
//there is no guarantee that prints will be in order
// we will use its initial thread->num ,cause it differs for each thread
//plus you will see how threads will behave
int order=my_data->thread_num;
printf("%i) before num T: %i\n",order, my_data->thread_num);
my_data->thread_num=4;
printf("%i) after assignment num T: %i\n",order ,my_data->thread_num);
return NULL;
}
int main(int argc, char *argv[])
{
int i;
ThreadData thread[N];
for(i=0; i<N; i++)
{
thread[i].thread_num=i;
pthread_create(&(thread[i].thread_id), NULL, thread_start, (void *)(thread+i));
}
//wait for all threads
for (i = 0; i < N; i++)
pthread_join(thread[i].thread_id, NULL);
//print results of each thread
for (i = 0; i < N; i++)
printf(" %i)thread: number %i\n",i,thread[i].thread_num);
return 0;
}
I can see multiple mistakes in your code.
First you have your pointers wrong. In the first example, it is enough to pass &pthread_data to pthread_create, &thread is the address of the thread pointer, so you are passing struct thread ** to your function instead of struct thread *. In the second example you should use (void *) thread[i]. &thread[i] is again struct thread **.
When you want each thread to write to its own thread data, then you should make an array of thread data, so that each thread has its own piece, else you will run into race conditions.
As others have already pointed out, you should call pthread_join before calling printf to ensure that the main thread will wait for all worker threads.
Also note that if you are calling pthread_join from other function that the one that spawned those threads, you have to ensure that the array of tread data will not go out of scope (in this case it would be probably better to use malloc or a global array).
You can't. As soon as main exits, which it does when you call pthread_exit, pthread_data ceases to exist, since it's local to the main function. So it can't be modified.

Linux Pthread argument

This is my code. It's very simple.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void *arg)
{
printf("ID=%d\n", *(int*)arg);
pthread_exit(NULL);
}
int main()
{
pthread_t pt[4];
int i;
for (i = 0; i < 4; i++)
{
int temp = i;
pthread_create(&pt[i], NULL, func, (void*)&temp);
}
sleep(1);
return 0;
}
I compiled it:
gcc p_test.c -lpthread
I ran it. It printed 2 2 3 3. I ran it again. It printed 2 3 3 2.
My problem is:
Why was 2 or 3 printed twice?
Why didn't it print 1 3 2 0 or any other results?
The major problem here is that you're taking the address of the local variable temp, and then using that pointer outside the scope of the variable - as soon as you exit one iteration of the loop, your pointer to temp becomes invalid and you must not dereference it.
You're passing a pointer to a temporary variable into the thread creation function and this temporary goes out of scope at the end of the loop block. It would seem to me that the temporary address is being reused by the compiler and so that when the threads are executing, they see the same address location.
If you do:
int *temp = malloc(sizeof(int));
*temp = i;
pthread_create(&pt[i], NULL, func, (void*)temp);
instead, you should see the results you expect.
In this case, the thread function needs to free the int after it is printed it to avoid a memory leak.
Also, it's better practice to pthread_join() the threads that you're waiting for rather than just sleep()ing.
because it prints temp, all threads shares the memory(why temp is "shared" is explained by TheJuice), so all threads "share" temp . Use a mutex or make temp a private variable.
Private Variables in Threads
Or you can use phtread_join like this:
int main()
{
pthread_t pt[4];
int i;
for (i =0 ; i < 4; i++)
{
pthread_create(&pt[i], NULL, func, (void*)&i);
pthread_join(pt[i],NULL);
}
//sleep(1);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void* arg)
{
printf("ID=%d\n", (int)arg);
pthread_exit(NULL);
return 0;
}
int main()
{
pthread_t pt[4];
int i;
for (i =0 ; i < 4; i++)
{
pthread_create(&pt[i], NULL, func, (void*)i);
pthread_join(pt[i],NULL);
}
return 0;
}

Resources