Thread Local Storage in C Language Concurrency: pthread_key_create

Thread Local Storage in C Language Concurrency: pthread_key_create

In multithreaded programming, managing data sharing between threads is an important issue. Especially in C language, due to its direct memory manipulation characteristics, using data appropriately can become complex. In this article, we will delve into “Thread Local Storage” and how to implement this feature using the <span>pthread_key_create</span> function.

What is Thread Local Storage (TLS)

Thread Local Storage is a mechanism that allows each thread to have its own independent copy of data, which can be accessed by multiple threads without causing data conflicts. For example, in a multi-user application, each user may have their own session information. By using TLS, we can ensure that each user’s information is isolated from others, preventing interference.

Introduction to pthread_key_create Function

Under the POSIX standard, thread local storage can be created and manipulated using the <span>pthread_key_t</span> type and a series of related functions. Specifically, the commonly used functions include:

  • <span>pthread_key_create</span>: Creates a key for TLS.
  • <span>pthread_setspecific</span>: Sets the value associated with the key.
  • <span>pthread_getspecific</span>: Retrieves the value associated with the key.
  • <span>pthread_key_delete</span>: Deletes the previously created key.

These functions provide independent data space for each newly created thread, allowing different threads to maintain their own data independently.

Parameter Explanation of pthread_key_create

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
  • <span>key</span>: A pointer to return the newly created key (i.e., TLS key).
  • <span>destructor</span>: An optional parameter; when the associated value is released, this destructor function will be called to clean up memory.

If you set this parameter to NULL, the system will not perform any automatic cleanup when the associated value is no longer needed.

Example Code

Next, let us demonstrate how to use <span>pthread_key_create</span> to implement a simple example. In this example, we simulate multiple worker threads, each having its own counter, and release these counter resources when the thread exits.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define NUM_THREADS 5
// Define a key for accessing each thread's counter
pthread_key_t thread_specific_data;
// Destructor function to free resources
void destructor(void* data) { free(data); }
// Function to record the current thread's counter and increment it
void* worker(void *arg) {
    // Allocate storage for the current thread's counter
    int *counter = malloc(sizeof(int));
    *counter = 0;
    // Bind it to the current thread
    pthread_setspecific(thread_specific_data, counter);
    for (int i = 0; i < 10; ++i) {
        (*counter)++;
        printf("Thread %ld: Counter Value: %d\n", (long)arg, *counter);
        usleep(10000); // Simulate some workload with a brief sleep
    }
    return NULL;
}
int main() {
    pthread_t threads[NUM_THREADS];
    // Create a key for TLS
    if (pthread_key_create(&thread_specific_data, destructor)) {
        fprintf(stderr, "Failed to create key\n");
        return EXIT_FAILURE;
    }
    // Start all threads
    for (long i = 0; i < NUM_THREADS; ++i) {
        if (pthread_create(&threads[i], NULL, worker, (void *)i)) {
            fprintf(stderr,"Error creating thread\n");
            return EXIT_FAILURE;
        }
    }
    // Wait for all threads to finish
    for(int i=0;i<NUM_THREADS;i++){
        if(pthread_join(threads[i], NULL)){
            fprintf(stderr,"Error joining thread\n");
            return EXIT_FAILURE;
        }
    }
    // Cleanup
    if(pthread_key_delete(thread_specific_data)) {
        fprintf(stderr, "Failed to delete key\n");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Notes:

  • Be cautious of potential deadlocks: When frequently updating resources, be careful of potential deadlock issues. Consider adding synchronization mechanisms as needed to ensure coordination accuracy.

Leave a Comment