Implementing thread-safe, dynamically resizable arrays in C is indeed a crucial topic for mastering advanced C programming and concurrency control. This knowledge can be essential when dealing with multi-threaded applications where data structures need to be accessed and modified concurrently.

Here's an overview of how you can achieve this:

Thread-Safe Dynamic Arrays in C

Key Concepts

Implementation Steps

Define the Dynamic Array Structure

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

typedef struct {
    int *data;
    size_t size;
    size_t capacity;
    pthread_mutex_t lock;
} DynamicArray;

Initialize the Dynamic Array

void initArray(DynamicArray *arr, size_t initialCapacity) {
    arr->data = (int *)malloc(initialCapacity * sizeof(int));
    arr->size = 0;
    arr->capacity = initialCapacity;
    pthread_mutex_init(&arr->lock, NULL);
}

Resize the Array

void resizeArray(DynamicArray *arr) {
    arr->capacity *= 2;
    arr->data = (int *)realloc(arr->data, arr->capacity * sizeof(int));
}

Add Elements to the Array

void addElement(DynamicArray *arr, int element) {
    pthread_mutex_lock(&arr->lock);
    if (arr->size == arr->capacity) {
        resizeArray(arr);
    }
    arr->data[arr->size++] = element;
    pthread_mutex_unlock(&arr->lock);
}

Remove Elements from the Array

void removeElement(DynamicArray *arr) {
    pthread_mutex_lock(&arr->lock);
    if (arr->size > 0) {
        arr->size--;
        // Optionally resize down if too much unused capacity
    }
    pthread_mutex_unlock(&arr->lock);
}

Clean Up

void freeArray(DynamicArray *arr) {
    free(arr->data);
    pthread_mutex_destroy(&arr->lock);
}

Example Usage

Here's a simple example of how you might use this dynamic array in a multi-threaded context:

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

#define NUM_THREADS 4
#define NUM_ELEMENTS 10

void *threadFunc(void *arg) {
    DynamicArray *arr = (DynamicArray *)arg;
    for (int i = 0; i < NUM_ELEMENTS; i++) {
        addElement(arr, i);
    }
    return NULL;
}

int main() {
    DynamicArray arr;
    initArray(&arr, 4);

    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&threads[i], NULL, threadFunc, &arr);
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    for (size_t i = 0; i < arr.size; i++) {
        printf("%d ", arr.data[i]);
    }
    printf("\n");

    freeArray(&arr);
    return 0;
}

Conclusion

Implementing a thread-safe, dynamically resizable array in C involves careful handling of memory allocation and synchronization. By using mutexes and condition variables, you can ensure that your data structures are safe for concurrent access and modifications, providing a robust foundation for multi-threaded applications.