0

I am learning pthreads.

Right now I am trying to make the program that writes to one 2d array using multiple pthreads. Each pthread is responsible for only one line of the array. So there is no race or overlap there. The goal is to make it as fast as possible without using global variables.

The first solution that I implemented was the one that uses a global variable. And it works as intended. Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int **array;
const int NTHREADS = 5;
const int ELEMENTS = 3;

void *worker(void *arg);
void print_array(int **array);

int main()
{
    int i, j;
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));

    array = (int**)malloc(sizeof(int*));
    for(i = -1; i < NTHREADS; i++)
    {
        array[i] = (int*)malloc(sizeof(int));
        for (j = -1; j < ELEMENTS; j++)
        {
            array[i][j] = (int)malloc(sizeof(int));
        }
    }

    for (i = 0; i < NTHREADS; i++)
        pthread_create(&threads[i], NULL, worker, (void*)i);

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(array);
    return 0;
}

void *worker(void *arg)
{
    int tid = (int)arg;

    for (int j = 0; j < ELEMENTS; j++)
        array[tid][j] = j;
    return (NULL);
}

void print_array(int **array)
{
    for (int i = 0; i < NTHREADS; i++)
    {
        for (int j = 0; j < ELEMENTS; j++)
            printf("%d,", array[i][j]);

        printf("\n");
    }
}

Then I wrote the same program using struct instead of global variable. Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

const int NTHREADS = 5;
const int ELEMENTS = 3;

typedef struct          s_asd
{
    int                 **array;
    int                 tid;
}                       t_asd;

void *worker(void *arg);
void print_array(int **array);

int main()
{
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
    t_asd tmp;
    int i, j;

    tmp.array = (int**)malloc(sizeof(int*));
    for (i = 0; i <= NTHREADS; i++)
    {
        tmp.array[i] = (int*)malloc(sizeof(int));
        for (j = 0; j <= ELEMENTS; j++)
            tmp.array[i][j] = (int)malloc(sizeof(int));
    }

    for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++)
        pthread_create(&threads[tmp.tid], NULL, worker, &tmp);

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(tmp.array);
    return 0;
}

void *worker(void *arg)
{
    t_asd   *tmp = (t_asd*)arg;

    for (int j = 0; j < ELEMENTS; j++)
        tmp->array[tmp->tid][j] = j;
    return (NULL);
}

void print_array(int **array)
{
    for (int i = 0; i < NTHREADS; i++)
    {
        for (int j = 0; j < ELEMENTS; j++)
            printf("%d,", array[i][j]);

        printf("\n");
    }
}

This one, prints random numbers. I know that I am using the same pointer in all threads, but threads themselves, are not using the same memory area. So why does it prints random numbers? What is the best solution, without using a global variable?

Update 1. Output of the second program:

-1413467520,32668,-1413467440,
-1413467584,-1413467568,-1413467552,
-1413467504,-1413467488,-1413467472,
0,1,2,
0,1,2,
17
  • Can you show the output please ? Commented May 16, 2017 at 12:30
  • You should use mutexes to avoid concurrent access. Commented May 16, 2017 at 12:33
  • Your use of malloc is wrong. array = (int**)malloc(sizeof(int*)); only allocates space for one pointer. Commented May 16, 2017 at 12:35
  • @ShellCode I updated the question with the output of the second program. Output itself may vary. And garbage values will be in different places. Commented May 16, 2017 at 12:54
  • 2
    All of these mallocs are very wrong. One never casts the return value of malloc in C - in your case the cast in (int)malloc(sizeof(int)) masked a valid warning / error. Commented May 16, 2017 at 13:02

2 Answers 2

1

Try something like that :

int main()
{
    pthread_t* threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));
    t_asd tmp;
    int i, j;

    tmp.array = (int**)malloc(NTHREADS * sizeof(int*));
    for (i = 0; i <= NTHREADS; i++)
    {
        tmp.array[i] = (int*)malloc(ELEMENTS * sizeof(int));

        //can be deleted if you want
        for (j = 0; j <= ELEMENTS; j++)
            tmp.array[i][j] = 0;
    }

    for (tmp.tid = 0; tmp.tid < NTHREADS; tmp.tid++) {
        t_asd *arg = (t_asd *) malloc(sizeof(t_asd));
        memcpy(arg, &tmp, sizeof(t_asd)); //will copy the current tid and the pointer to the array in a new memory area
        pthread_create(&threads[tmp.tid], NULL, worker, arg);
    }

    for (i = 0; i < NTHREADS; i++)
        pthread_join(threads[i], NULL);

    print_array(tmp.array);
    return 0;
}

Of course this is an example and you have to free all the allocations

Sign up to request clarification or add additional context in comments.

3 Comments

This code works. And if I am understanding correctly, this is basically the same as the method Andriy Berestovskyy suggested, just different implementation? But I have one question. If tmp instead of stack allocated struct will be dynamically allocated pointer to a struct. And it will be big. (Containing bunch of pointer and variables) Will memcpy take a long time to copy?
Yes it's the same idea Andriy and I are suggesting. I'm pretty sure the complexity of memset will never exceed O(n) but I think you don't have to worry about this, because you are just copying pointers, not all the data
Thank you very much. Will try this implementation, with fractal rendering. Will report when it will be ready. :) For now, I will mark this question answered.
1

You are passing local variable tmp as an argument to the thread and changing it in a loop at the same time. This is a data race and your threads most probably will operate over the same data.

Convert tmp to an array, fill and pass a corresponding element to a corresponding thread.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.