Skip to content

Latest commit

 

History

History
183 lines (121 loc) · 6.46 KB

File metadata and controls

183 lines (121 loc) · 6.46 KB

Pthread

The POSIX thread (pthread) is based on the POSIX Threads standard, which defines a set of functions and data types for creating and controlling threads in a portable and consistent manner. PThread is a widely-used implementation of this standard, and is commonly used in multi-threaded programming on Linux and other Unix-like operating systems.

PThread level of control can be useful in some cases, but it can also make the programming of concurrent applications more complex and error-prone.

Basic recap of threads

A thread is a unit of execution within a process that can be scheduled and executed by the operating system. In the Shared Memory Model, threads have their own local resources, such as stack and register state, but they also have access to the shared resources of the process in which they run. This allows multiple threads to cooperate since they can communicate with each other implicitly by reading and writing to shared system memory locations. However, this can lead to sync issues and the programmer must use mechanisms to ensure that threads access shared resources in a safe and orderly manner.

Threads created in a pthread application are not hierarchically organized. In the pthread library, threads are considered to be independent entities that can be scheduled and executed by the operating system in an arbitrary order.

Main Pthread functions

pthread_create

int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine)(void *), void * arg)
  1. thread, is a pointer to a pthread_t variable that will be set to the ID of the newly created thread.

  2. attr, is a pointer to a pthread_attr_t structure that specifies optional attributes for the new thread. This parameter can be set to NULL to use the default values for all attributes.

  3. start_routine, is a pointer to a function that will be executed by the new thread when it is created. This function must have a return type of void * and take a single void * argument.

  4. arg, is a pointer to data that will be passed as an argument to the start_routine function when the new thread is created.

struct thread_args {
    int arg1;
    char *arg2;
};

void * my_thread_func(void *args) {
    //remember the cast
    struct thread_args * my_args = (struct thread_args *) args;
    int arg1 = my_args->arg1;
    char *arg2 = my_args->arg2;
    // Use the arguments in the thread function...
}

int main() {
    pthread_t my_thread;
    struct thread_args my_args;

    my_args.arg1 = 10;
    my_args.arg2 = "hello";

    pthread_create(&my_thread, NULL, my_thread_func, &my_args);

    // Other code...
}

Note that an important step in pthreads to communicate variables is how void *args works: in this example the struct thread_args is defined to contain the two arguments that will be passed to the thread function. The generalization of this approach is to pass arguments of any type to a thread function as long as you define a struct that can hold the necessary data and pass a pointer to this struct to pthread_create.

pthread_join

Pthread_join is a function used in the POSIX thread (pthread) library to synchronize the execution of threads. It allows one thread to wait for the completion of another thread. When a thread calls pthread_join, it is suspended until the target thread (the thread being joined) completes its execution. The pthread_join function returns the exit status of the target thread, which can be used to determine whether it terminated successfully or not.

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

void *my_thread_func(void *args) {
    // Do some work in the thread...
    return NULL;
}

int main() {
    pthread_t my_thread;

    pthread_create(&my_thread, NULL, my_thread_func, NULL);

    // Do some work in the main thread...

    pthread_join(my_thread, NULL);

    // Continue execution after the thread has completed...

    return 0;
}

pthread_barrier_t

pthread_barrier_init(pthread_barrier_t barrier, pthread_barrierattr_t * attr, unsigned int count); 

count is the number of variable to wait. attr is the number of variable to wait.

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

pthread_barrier_t my_barrier;

void *my_thread_func(void *args) {
    // Do some work in the thread...

    pthread_barrier_wait(&my_barrier);

    // Continue execution after the barrier is reached...

    return NULL;
}

int main() {
    pthread_barrier_init(&my_barrier, NULL, 2);

    pthread_t my_thread;
    pthread_create(&my_thread, NULL, my_thread_func, NULL);

    // Do some work in the main thread...

    pthread_barrier_wait(&my_barrier);

    // Continue execution after the barrier is reached...

    pthread_join(my_thread, NULL);

    return 0;
}

Both the main thread and the new thread do some work, and then each calls the pthread_barrier_wait(&barrier) function to wait for the other thread to reach the barrier. When both threads have reached the barrier, they are released and can continue execution.

Cond and mutex

A mutex variable is a special type of lock that allows only one thread to hold it at any given time. When a thread acquires a mutex, it prevents other threads from acquiring the same mutex, ensuring that only one thread can access the protected resource at a time.

The pthread_cond_wait function release the mutex that is associated with the condition variable. This allows other threads to acquire the mutex and access the shared resource or data structure that is protected by the mutex.

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

pthread_mutex_t my_mutex;
pthread_cond_t my_cond;
int my_shared_var = 0;

void *my_thread_func(void *args) {
    pthread_mutex_lock(&my_mutex);

    // Wait for the condition to be signaled
    while (my_shared_var == 0) {
        pthread_cond_wait(&my_cond, &my_mutex);
    }

    // Do some work with the shared variable...

    pthread_mutex_unlock(&my_mutex);
    return NULL;
}

int main() {
    pthread_mutex_init(&my_mutex, NULL);
    pthread_cond_init(&my_cond, NULL);

    pthread_t my_thread;
    pthread_create(&my_thread, NULL, my_thread_func, NULL);

    // Do some work in the main thread...
    pthread_mutex_lock(&my_mutex);
    my_shared_var = 1;
    pthread_cond_signal(&my_cond);
    pthread_mutex_unlock(&my_mutex);

    pthread_join(my_thread, NULL);

    return 0;
}

pthread_cond_signal(&cond) signals only 1 thread! pthread_cond_broadcast(&cond) signals all the threads that are "listening" that condition variable.