Parallel programming using pthread - c

I have just started learning parallel programming using pthreads. So, for the learning purpose I tried sum of two integer arrays parallely. I have declared struct construct with three array variables a, b and c. I want to do addition of a, b and store the result in c.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define MAX 6
struct data {
int a[MAX];
int b[MAX];
int c[MAX];
};
void *addition(void *index) {
struct data *d1 = (struct data *)index;
printf("value of d1 structure=%d\n", d1->a[0]);
}
int main() {
int i, j, t;
struct data *item = NULL;
pthread_t threads[MAX];
item = (struct data *)malloc(sizeof *item);
printf("enter the value for arrray a\n");
for (i = 0; i < MAX; i++) {
scanf("%d", &item->a[i]);
}
printf("enter the value of array b\n");
for (j = 0; j < MAX; j++) {
scanf("%d", &item->b[j]);
}
for (t = 0; t < MAX; t++) {
pthread_create(&threads[t], NULL, addition, (void *)&item);
}
}
Here, as of now I have not added the addition of arrays in the function addition(), because in pthread_create() when I am passing the three arguments with the help of structure, in function addition the variables a and b are not getting copied. Printing a is giving me garbage value. Can anybody help me how to copy the structure variable to the function argument called by pthread_create().

pthread_create Function :
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Kindly note (*arg) is pointer to the arg.
You have created struct data *item as a pointer then you are passing its address i.e. pointer to pointer.
pthread_create(&threads[t], NULL, addition, (void *)&item);
Change the call to
pthread_create(&threads[t], NULL, addition, (void *)item).

Related

Passing struct data arguments to threads

I'm confused on how to pass struct arguments to threads in the for loop.
When I try with this approach, I get garbage port values. When I try to change the struct to just astruct argstruct; without the pointer, the second port overwrites the first one so I get 200 200 printed.
Also, would I have to free the struct in main, Func, or both?
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
void* Func(void* pstruct);
typedef struct thread_args{
int port;
} astruct;
int main()
{
int peers[2] = {100,200};
pthread_t threads[2];
astruct *argstruct[2];
for (int i = 0; i < 2; i++) {
argstruct[i] = malloc(sizeof(astruct));
argstruct[i]->port = peers[i];
pthread_create(&threads[i],NULL,Func,&argstruct[i]);
}
for(int i = 0; i < 2; i++){
pthread_join(threads[i], NULL);
}
return 0;
}
void* Func(void* pstruct){
int port;
astruct *argstruct = (astruct *)pstruct;
port = argstruct->port;
printf("port: %d\n", port);
return 0;
}
I'm confused on how to pass struct arguments to threads in the for loop.
argstruct[i] elements are pointers, you don't need address operator:
pthread_create(&threads[i], NULL, Func, argstruct[i]);
Note that you wouldn't need memory allocation for this simple case, you can use a local array:
//...
astruct argstruct[2];
for (int i = 0; i < 2; i++) {
argstruct[i].port = peers[i];
pthread_create(&threads[i], NULL, Func, &argstruct[i]);
}
//...
Also, would I have to free the struct in main, Func, or both?
You should free it one time only. The procedure is always the same, you free it when you don't need it anymore, that can be in the the thread routine or in main.
In your example, you could very well free the memory after port = argstruct->port; as you no longer use it after this assignment:
void* Func(void* pstruct){
int port;
astruct *argstruct = (astruct *)pstruct;
port = argstruct->port;
free(argstruct); //<-- here
printf("port: %d\n", port);
return 0;
}

How can I pass an array as a return value through a thread?

I am working on a function that creates a thread and calculates the Fibonacci sequence to a certain user inputted value. For example, if a user enters 5, the output will be: 0 1 1 2 3 5
However, the sequence must be calculated in the created thread, and the results have to be printed out after the thread is exited.
I can create the thread and calculate the sequence, but I need to pass the array fibSequence[] back to the original thread using pthread_exit and pthread_join. I am having trouble figuring out the syntax and can't find any examples of people passing arrays through.
What I have so far:
I created a function fib_runner() that is called by a newly created thread. The Fibonacci sequence is created and placed into the array fibSequence[]. I need to pass this back through to the main function. I am temporarily printing out the sequence in the function, but it should be printed in the main.
Thank you!
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* fib_runner(void* arg)
{
int *limit_ptr = (int*) arg;
int limit = *limit_ptr;
int fibSequence[limit];
int size = sizeof(fibSequence)/sizeof(fibSequence[0]);
printf("Size: %d\n", size);
fibSequence[0] = 0;
fibSequence[1] = 1;
for (int i = 2; i <= size; i++)
{
fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
}
for (int i = 0; i <= size; i++)
{
printf("%d ", fibSequence[i]);
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
int limit;
printf("Enter Number: ");
scanf("%d", &limit);
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid, &attr, fib_runner, &limit);
pthread_join(tid, NULL);
}
Currently, the array is a local variable, so it would go out of scope when the function exits. You need to dynamically allocate memory for it instead:
int *fibSequence = malloc(sizeof(int) * limit);
Then return this pointer from the function:
return fibSequence;
In your main function, you then pass the address of a pointer to receive this value. Then you can print the content of the array. When you're done, be sure to free it:
int *fibSequence;
pthread_join(tid, (void **)&fibSequence);
for (int i = 0; i < limit; i++)
{
printf("%d ", fibSequence[i]);
}
free(fibSequence);
Also, you don't need size in your thread function, since it is the same as limit, and the way you currently calculate it won't work anyway since you now have a pointer instead of an array. Your loop limit in fib_runner also goes one past the end of the array. The exit condition should be i < size, not i <= size.
you have to pass in a value of void * to pthread_exit which is pthread_exit(( void * ) &fibSequence, once that function is called the passed in value will populate the second argument to pthread_join, the second argument will be a pointer to a pointer void ** it will hold the values passed in to pthred_exit
All the threads running within a process share the same address space, file descriptors, stack and other process related attributes.
Threads are sharing memory by definition, they do not own anything except stack and local variables;
If you make fibSequence[limit] global then all threads will have access to it.
You can also declare fibSequence[limit] on the stack in main and pass pointer to it to your thread.
To pass multiple arguments it is convenient to wrap them up in a structure.
The solutions below employ:
struct arg_struct {
int limit;
int *ptrFib;
}args;
Program:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct arg_struct {
int limit;
int *ptrFib;
}args;
void* fib_runner(void* arg)
{
struct arg_struct *a = (struct arg_struct *) arg;
int size = a->limit;
int * fibSequence = a->ptrFib;
fibSequence[0] = 0;
fibSequence[1] = 1;
for (int i = 2; i <= size; i++){
fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
int limit;
printf("Enter Number: ");
scanf("%d", &limit);
int fibSequence[limit];
struct arg_struct argF;
argF.limit = limit;
argF.ptrFib = fibSequence;
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid, &attr, fib_runner, &argF);
pthread_join(tid, NULL);
for (int i = 0; i <= limit; i++){
printf("%d ", fibSequence[i]);
}
}
Output:
Enter Number: 5
0 1 1 2 3 5
The solution with global variable argF is of course possible but it is less elegant.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct arg_struct {
int limit;
int *ptrFib;
}args;
struct arg_struct argF;
void* fib_runner()
{
int size = argF.limit;
int * fibSequence = argF.ptrFib;
fibSequence[0] = 0;
fibSequence[1] = 1;
for (int i = 2; i <= size; i++){
fibSequence[i] = fibSequence[i-1] + fibSequence[i-2];
}
pthread_exit(0);
}
int main(int argc, char **argv)
{
int limit;
printf("Enter Number: ");
scanf("%d", &limit);
int fibSequence[limit];
argF.limit = limit;
argF.ptrFib = fibSequence;
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&tid, &attr, fib_runner, NULL);
pthread_join(tid, NULL);
for (int i = 0; i <= limit; i++){
printf("%d ", fibSequence[i]);
}
}

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.

Pass integer value through pthread_create

I simply want to pass the value of an integer to a thread.
How can I do that?
I tried:
int i;
pthread_t thread_tid[10];
for(i=0; i<10; i++)
{
pthread_create(&thread_tid[i], NULL, collector, i);
}
The thread method looks like this:
void *collector( void *arg)
{
int a = (int) arg;
...
I get the following warning:
warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
The compiler will complain if you don't cast i to a void pointer:
pthread_create(&thread_tid[i], NULL, collector, (void*)i);
That said, casting an integer to a pointer isn't strictly safe:
ISO/IEC 9899:201x
6.3.2.3 Pointers
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
so you're better off passing a separate pointer to each thread.
Here's a full working example, which passes each thread a pointer to a separate element in an array:
#include <pthread.h>
#include <stdio.h>
void * collector(void* arg)
{
int* a = (int*)arg;
printf("%d\n", *a);
return NULL;
}
int main()
{
int i, id[10];
pthread_t thread_tid[10];
for(i = 0; i < 10; i++) {
id[i] = i;
pthread_create(&thread_tid[i], NULL, collector, (void*)(id + i));
}
for(i = 0; i < 10; i++) {
pthread_join(thread_tid[i], NULL);
}
return 0;
}
There's a nice intro to pthreads here.
int is 32 bit, and void * is 64 bit in 64bit Linux; In that case you should use long int instead of int;
long int i;
pthread_create(&thread_id, NULL, fun, (void*)i);
int fun(void *i) function
long int id = (long int) i;
void *foo(void *i) {
int a = *((int *) i);
free(i);
}
int main {
int *arg = (char*)malloc(sizeof(char))
pthread_create(&thread, 0, foo, arg);
}
It better to use of a struct for send more parameters in one :
struct PARAMS
{
int i;
char c[255];
float f;
} params;
pthread_create(&thread_id, NULL, fun, (void*)(&params));
then you can cast params to PARAMS* and use of it in pthread routine:
PARAMS *p = static_cast<PARAMS*>(params);
p->i = 5;
strcpy(p->c, "hello");
p->f = 45.2;

pthread_create and passing an integer as the last argument

I have the following functions :
void *foo(void *i) {
int a = (int) i;
}
int main() {
pthread_t thread;
int i;
pthread_create(&thread, 0, foo, (void *) i);
}
At compilation, there are some errors about casting ((void *) i and int a = (int) i). How can I pass an integer as the last argument of pthread_create properly?
Building on szx's answer (so give him the credit), here's how it would work in your for loop:
void *foo(void *i) {
int a = *((int *) i);
free(i);
}
int main() {
pthread_t thread;
for ( int i = 0; i < 10; ++1 ) {
int *arg = malloc(sizeof(*arg));
if ( arg == NULL ) {
fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
exit(EXIT_FAILURE);
}
*arg = i;
pthread_create(&thread, 0, foo, arg);
}
/* Wait for threads, etc */
return 0;
}
On each iteration of the loop, you're allocating new memory, each with a different address, so the thing that gets passed to pthread_create() on each iteration is different, so none of your threads ends up trying to access the same memory and you don't get any thread safety issues in the way that you would if you just passed the address of i. In this case, you could also set up an array and pass the addresses of the elements.
You can allocate an int on the heap and pass it to pthread_create(). You can then deallocate it in your thread function:
void *foo(void *i) {
int a = *((int *) i);
free(i);
}
int main() {
pthread_t thread;
int *i = malloc(sizeof(*i));
pthread_create(&thread, 0, foo, (void *) i);
}
You should cast the address of i (rather than the value of i as you do now) in the last argument of pthread_create().
pthread_create(&thread, 0, foo, (void *) &i);
^ is missing
And the casting is wrong in your function too. It should be:
int a = *((int*) i);
If you intend to read the value, you should also initialize i to some value in main() as it's uninitialized now.
2 Use proper definition for main():
int main(void)
or int main(int argc, char *argv[]) or its equivalent.
Old question, but I faced the same problem today, and I decided not to follow this path.
My application was really about performance, so I chose to have this array of ints declared statically.
Since I don't know a lot of applications where your pthread_join / pthread_cancel is in another scope than your pthread_create, I chose this way :
#define NB_THREADS 4
void *job(void *_i) {
unsigned int i = *((unsigned int *) _i);
}
int main () {
unsigned int ints[NB_THREADS];
pthread_t threads[NB_THREADS];
for (unsigned int i = 0; i < NB_THREADS; ++i) {
ints[i] = i;
pthread_create(&threads[i], NULL, job, &ints[i]);
}
}
I find it more elegant, more efficient, and you don't have to worry about freeing since it only lives in this scope.
While this is an old question there is one option missing when all you need is to pass a positive integer like a descriptor: you can pass it directly as the address, while it it a hack it works well and avoid allocating anything :)
NOTE: the size of the integer must match the size of a pointer on your OS but nowadays most systems are native 64bits.
#include <pthread.h>
#include <inttypes.h>
#include <stdio.h>
void *_thread_loop(void *p)
{
uint64_t n = (uint64_t)p;
printf("received %llu\n", n);
return NULL;
}
int main(int argc, char const *argv[])
{
pthread_t read_thread_id;
uint64_t n = 42;
pthread_create(&read_thread_id, NULL, _thread_loop, (void *)n);
pthread_join(read_thread_id, NULL);
return 0;
}

Resources