'Create an dynamic array of buffers?

I'm trying to create an array of buffers.

I have a loop that does:

for(int i = 0; i < threadCount; i++){
    read(textFile, buffer, spacer);
    pthread_create(&myThread, NULL, processData, (void *)buffer);
}

The issue is that while the thread is running, the next iteration of the loop changes the buffer I'm assuming. And that makes the second loop not run correctly. Would I need to create an array? As in

char *array[threadCount]

And each index of that array is a buffer?

I'm not sure how I would allocate memory for that. If there's another obvious solution I'm missing, that would be great.

c


Solution 1:[1]

You are passing the same pointer to every thread. And you're repeatedly overwriting the memory to which that pointer points.

You have a similar problem with myThread. You place the thread id of every thread into the same variable.

You'll need an array of thread ids. For the buffer, you could create an array (as you mentioned) and pass the index. Or you could replace

pthread_t myThread;
char buffer[spacer];
for(int i = 0; i < threadCount; i++){
   read(textFile, buffer, spacer);
   pthread_create(&myThread, NULL, processData, buffer);
}

with something like

pthread_t myThreads[threadCount];
for(int i = 0; i < threadCount; i++){
   char *buffer = malloc(spacer);
   read(textFile, buffer, spacer);
   pthread_create(myThreads+i, NULL, processData, buffer);
}

(The thread is responsible for freeing the buffer.)

(Removed the useless cast.)

Solution 2:[2]

Given you're using dynamic allocation, the correct solution would typically be to change:

char *buffer = malloc(spacer);
// Check for allocation error here
for(int i = 0; i < threadCount; i++){
    read(textFile, buffer, spacer);
    pthread_create(&myThread, NULL, processData, (void *)buffer);
}
// Wait for threads and maybe do something with buffer here
free(buffer);

to:

char **buffers = malloc(threadCount * sizeof(*buffers));
// Check for allocation error here
// Alternative if relying on VLA support is okay, or threadCount is a program constant
// char *buffers[threadCount];
// saves an allocation and for non-absurd thread counts shouldn't be too hard on the stack

for(int i = 0; i < threadCount; i++){
    buffers[i] = malloc(spacer);
    // Check for allocation error here
}
for(int i = 0; i < threadCount; i++){
    read(textFile, buffers[i], spacer);
    pthread_create(&myThread, NULL, processData, (void *)buffers[i]);
}
// Wait for threads and maybe do something with buffers here
for(int i = 0; i < threadCount; i++){
    free(buffers[i]);
}
free(buffers); // Omit if buffers itself was not malloc-ed above

If the main thread doesn't need to use the contents of the buffers after the threads are done processing, you can have the threads free their own buffer when they're done with it and save the work in the main thread (the main thread would only be responsible for freeing the top level buffers array).

Solution 3:[3]

Example with a single one time allocation for both the array of pointers to buffers and the buffers themselves (assumes all buffers are the same size). The buffers are rounded up to 4 byte boundaries. As mentioned in ShadowRanger's answer, a debugger wouldn't catch out of bounds indexing on each buffer with this single allocation method. When running this program I had count set to 20 and buffer size set to 30 (it will be rounded up to 32). Buffer size just needs to be greater than zero (a size of 1 will get rounded up to 4) for the sprints().

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

int main(int argc, char**argv)
{
char **arr;
char *bfr;
int cnt;
int siz;
int i;

    /* get and check parameters */
    if(argc != 3)
        return 0;
    sscanf(argv[1], "%d", &cnt);
    sscanf(argv[2], "%d", &siz);
    if(cnt <= 0 || cnt > 99 || siz <= 0 || siz > 1024)
        return  0;
    /* single allocation, buffers rounded to 4 byte boundaries */
    arr = malloc((cnt*sizeof(char *))+(cnt*4*((siz+3)/4)));
    if(arr == NULL)
        return 0;
    /* optional - zero memory */
    memset(arr, 0, (cnt*sizeof(char *))+(cnt*4*((siz+3)/4)));
    /* initialize array of pointers to buffers */
    for(i = 0, bfr = (char *)(arr+cnt); i < cnt; i++, bfr += 4*((siz+3)/4))
        arr[i] = bfr;
    /* write integer strings to buffers for display */
    for(i = 0; i < cnt; i++)
        sprintf(arr[i], "%2d", i);
    /* display buffers */
    for(i = 0; i < cnt; i++)
        printf("%s\n", arr[i]);
    /* free allocated memory */
    free(arr);
    return 0;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 ShadowRanger
Solution 3