POSIX threads for Linux

brief description

POSIXA thread (Pthreads)is a standard multithreading APIthat provides a set of functions and data types that enable programmers to use multiple threads to perform tasks concurrently. POSIXThread support Unixruns on class operating systems and is cross-platform.

method

The following are some commonly used POSIXthread functions and data types:

pthread_t

Represents the data type of a thread, which is an opaque structure type, usually implemented as a pointer to a thread control block (Thread Control Block, TCB). defined in the <pthread.h>header file

pthread_create()

This function is used to create a new thread. Its prototype is as follows:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

Parameter Description:

  • thread: Point to the new thread ID, if the thread is created successfully, it will be filled as the new thread ID.
  • attr: Used to set the properties of the new thread, if passed in NULL, the default thread properties will be used.
  • start_routine: is the entry function of the new thread, it is a function pointer, pointing to the function to be executed by the new thread
  • arg: is the parameter passed to start_routinethe function

When pthread_create()the function , a new thread is created and the new thread executes start_routinethe function. If start_routinethe function executes successfully and exits normally, the new thread will exit automatically, and pthread_join()the exit status of the new thread can be obtained by calling the function. If start_routinethe function encounters an error or exits abnormally

pthread_join()

Functions to wait for the end of a thread and get its exit status. Its prototype is as follows:

int pthread_join(pthread_t thread, void **retval);

Parameter Description:

  • thread: The thread to wait on ID.
  • retval: The return value of the thread, which can be NULL.

pthread_exit()

This function is used to terminate a thread within a thread. It can return a value, or return nothing.

void pthread_exit(void *value_ptr);

Parameter Description:

  • value_ptr: As the exit status of the thread, it notifies other threads of the execution of the thread.

pthread_mutex_t

This data type represents a mutex. A mutex is a synchronization mechanism used to control access to shared resources. Its prototype is as follows:

typedef struct {
    
    
    // ...
} pthread_mutex_t;

pthread_mutex_init()

This function is used to dynamically initialize a mutex. Its prototype is as follows:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

And PTHREAD_MUTEX_INITIALIZERfor statically defined mutexes, that is, mutexes that have been determined at compile time.

eg:

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;

Parameter Description:

  • mutex: The mutex to initialize.
  • attr: The attribute of the mutex, which can be NULL.

pthread_mutex_lock()

This function is used to acquire a mutex. If the mutex is already held by another thread, the current thread blocks. Its prototype is as follows:

int pthread_mutex_lock(pthread_mutex_t *mutex);

Parameter Description:

  • mutex: The mutex to acquire.

pthread_mutex_unlock()

This function is used to release the mutex. Its prototype is as follows:

int pthread_mutex_unlock(pthread_mutex_t *mutex);

Parameter Description:

  • mutex: The mutex to be released.

pthread_mutex_destroy()

The function used to destroy the mutex, its prototype is as follows:

int pthread_mutex_destroy(pthread_mutex_t *mutex);

Parameter Description:

  • mutex: Pointer to the mutex.

pthread_cond_t

This data type is used to realize the synchronization of condition variables between threads (that is, to pass signals between different threads). It is commonly used with functions such as pthread_cond_wait(), , andpthread_cond_signal() . pthread_cond_broadcast()Its prototype is as follows:

typedef struct {
    
    
    // ...
} pthread_cond_t;

Condition variables can be initialized with pthread_cond_init()or .PTHREAD_COND_INITIALIZER

pthread_cond_init()

This function is used to initialize condition variables. Its prototype is as follows:

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

Parameter Description:

  • cond: The condition variable to initialize.
  • attr: Property of the condition variable, can be NULL.

pthread_cond_wait()

The function of this function is to block the thread while waiting for the value of the condition variable to become non-zero and wait for the condition variable to be awakened by a signal from another thread.
When a thread calls it pthread_cond_wait(), it will block until another thread calls pthread_cond_signal()or pthread_cond_broadcast()to notify it that the condition has been met. Its prototype is as follows:

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

Parameter Description:

  • cond: Condition variable pointer.
  • mutex: Mutex pointer. The lock needs to be acquired before calling this function, and the lock will be released automatically before the function returns.

pthread_cond_signal()

It is used to broadcast a signal to threads waiting on a condition variable, and wake up a thread waiting on the condition variable. If there are multiple threads waiting, only one of them will be woken up. This operation has no effect if there are no waiting threads. It is usually used in pthread_cond_wait()conjunction to synchronize condition variables between threads.

int pthread_cond_signal(pthread_cond_t *cond);

Parameter Description:

  • cond: Condition variable pointer.

pthread_cond_broadcast()

It is used to broadcast a signal to threads waiting for a condition variable to wake up all threads waiting for the condition variable. It is usually used in pthread_cond_wait()conjunction to synchronize condition variables between threads. Its prototype is as follows:

int pthread_cond_broadcast(pthread_cond_t *cond);

Parameter Description:

  • cond: Condition variable pointer.

pthread_cond_destroy()

Function to destroy condition variables. Its prototype is as follows:

int pthread_cond_destroy(pthread_cond_t *cond);

sem_t

It is an opaque data structure, defined in <semaphore.h>the header file, used to represent a semaphore. sem_tVariables are usually created by sem_init()the function and sem_destroy()destroyed by the function when they are done using

sem_init()

Used to initialize a semaphore. Its prototype is as follows:

int sem_init(sem_t *sem, int pshared, unsigned int value);

Parameter Description:

  • sem: Pointer to the semaphore variable that needs to be initialized.
  • pshared: Specify the type of semaphore, the value can be 0or 1. psharedWhen the value 0of is , it means that the semaphore can only be shared among multiple threads of the current process; when psharedthe value 1of is , it means that the semaphore can be shared among multiple processes.
  • value: Specifies the initial value of the semaphore. The value of the semaphore must be a non-negative integer representing the available amount of the resource. Typically, an initial value of 1indicates that only one resource is available, and an initial value of 0indicates that no resource is available.

sem_wait()

It is used to obtain (wait) a semaphore, that is, perform P operation on the semaphore (wait operation: when a thread or process needs to occupy resources, it will try to perform P operation to obtain the semaphore. If the value of the semaphore is greater than 0, then Decrement the value of the semaphore and continue execution; otherwise, the thread or process blocks waiting for the value of the semaphore to be greater than 0),

int sem_wait(sem_t *sem);

Parameter Description:

  • sem: Pointer to the semaphore variable.

sem_post()

It is used to release (send) a semaphore, that is, perform V operation on the semaphore (release operation: when a thread or process no longer needs to occupy resources, it will perform V operation to release the semaphore. This operation increases the value of the semaphore 1 to notify other threads or processes that execution can continue).

int sem_post(sem_t *sem);

Parameter Description:

  • sem: Pointer to the semaphore variable.

sem_destroy()

Used to destroy an initialized semaphore. Its prototype is as follows:

int sem_destroy(sem_t *sem);

Parameter Description:

  • sem: Pointer to the semaphore variable.

pthread_key_t

Used to create thread-private data ( Thread-Specific Data, for short TSD). Thread-private data means that each thread has an independent data space, and the data between threads will not affect each other. In a multi-threaded program, it is sometimes necessary to allocate an independent data space for each thread so that the threads can access and modify data independently.

pthread_key_create()

Create a key for thread-private data.

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))

Parameter Description:

  • key: is a pointer to pthread_key_tthe type used to store the key of the created thread private data
  • destructor : is a callback function used to automatically release thread private data when the thread exits. If you do not need to automatically release thread-private data, you can set destructorthe parameter to NULL.
  • Returns 0 when the function executes successfully, otherwise returns a non-zero error code.

pthread_setspecific()

Set thread-private data for the current thread

int pthread_setspecific(pthread_key_t key, const void *value)

Parameter Description:

  • key: is the key of a thread private data
  • value: is a pointer to data, used to set the value of thread private data
  • Returns 0 when the function executes successfully, otherwise returns a non-zero error code

pthread_getspecific()

Get the thread-private data of the current thread

void *pthread_getspecific(pthread_key_t key)

Parameter Description:

  • key: It is a key of thread-private data, which is used to obtain the value of thread-private data.
  • The function returns a pointer to the thread private data, if the thread does not set the thread private data, returns NULL.

pthread_key_delete()

Deletes a key for thread-private data

int pthread_key_delete(pthread_key_t key)

Parameter Description:

  • key: A key of thread-private data, used to delete the key and the corresponding thread-private data.
  • If the thread-private data key is successfully deleted, the function returns 0, otherwise it returns a non-zero error code.

pthread_once_t

POSIXA type in the thread library, used to represent the control variable in the pthread_once function, used to ensure that a function will only be executed once. It is actually a volatile int type, that is to say, it is volatilea inttype variable, so it can be guaranteed that the read and write operations of the value of this variable will not be optimized or reordered in multi-threaded programs.

Its prototype is:

typedef volatile int pthread_once_t;

pthread_once_tThe initialization of variables should use PTHREAD_ONCE_INITthe macro , which is defined pthread.hin the header file, and its definition is as follows:

#define PTHREAD_ONCE_INIT   0

It should be noted that pthread_once_tthe variable must be a static variable or a global variable, otherwise race conditions may occur. In addition, since the read and write operations of pthread_once_t the variable need to ensure atomicity and visibility, the memory model and synchronization mechanism must be followed when using the variable.

pthread_key_delete()

Used to ensure that a function will only be executed once. In multi-threaded programming, when multiple threads need to execute the same initialization function, the pthread_once function can be used to ensure that the function will only be executed once, thereby avoiding the race condition problem caused by concurrent access.
Its prototype is as follows:

int pthread_once(pthread_once_t* once_control, void (*init_func)(void));

Parameter Description:

  • once_control: a pointer to a variable of type pthread_once_t
  • init_func: A function pointer, indicating the initialization function that needs to be guaranteed to be executed only once

example

create thread

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

void *thread_function(void *arg) {
    
    
  printf("Hello from thread!\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int ret = pthread_create(&my_thread, NULL, thread_function, NULL);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread!
Thread joined.
*/

Pass parameters to thread

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

void *thread_function(void *arg) {
    
    
  int *num_ptr = (int *)arg;
  printf("Hello from thread! The number is %d.\n", *num_ptr);
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int num = 42;
  int ret = pthread_create(&my_thread, NULL, thread_function, &num);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread! The number is 42.
Thread joined.
*/

Thread synchronization (using mutexes)

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

int counter = 0;
pthread_mutex_t counter_mutex;

void *thread_function(void *arg) {
    
    
  int i; 
  for (i = 0; i < 1000000; i++) {
    
    
    pthread_mutex_lock(&counter_mutex);
    counter++;
    pthread_mutex_unlock(&counter_mutex);
  }
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t threads[4];
  pthread_mutex_init(&counter_mutex, NULL);
  int i; 
  for (i = 0; i < 4; i++) {
    
    
    pthread_create(&threads[i], NULL, thread_function, NULL);
  }
  for (i = 0; i < 4; i++) {
    
    
    pthread_join(threads[i], NULL);
  }
  pthread_mutex_destroy(&counter_mutex);
  printf("Counter value: %d\n", counter);
  return 0;
}
/*
执行结果:
Counter value: 4000000
*/

Thread synchronization (using condition variables)

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

bool flag = false;
pthread_mutex_t flag_mutex;
pthread_cond_t flag_cond;

void *thread_function(void *arg) {
    
    
  printf("Thread waiting for flag to be set...\n");
  pthread_mutex_lock(&flag_mutex);
  while (!flag) {
    
    
	printf("go thread here start...\n");
    pthread_cond_wait(&flag_cond, &flag_mutex);
	printf("go thread here end...\n");
  }
  pthread_mutex_unlock(&flag_mutex);
  printf("Flag has been set, thread exiting.\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  pthread_mutex_init(&flag_mutex, NULL);
  pthread_cond_init(&flag_cond, NULL);
  pthread_create(&my_thread, NULL, thread_function, NULL);
  sleep(1);
  printf("Setting flag to true...\n");
  pthread_mutex_lock(&flag_mutex);
  flag = true;
  printf("go main here start...\n");
  pthread_cond_signal(&flag_cond);
  printf("go main here mid...\n");
  pthread_mutex_unlock(&flag_mutex);
  printf("go main here end...\n");
  pthread_join(my_thread, NULL);
  pthread_mutex_destroy(&flag_mutex);
  pthread_cond_destroy(&flag_cond);
  return 0;
}
/*
执行结果:
Thread waiting for flag to be set...
go thread here start...
Setting flag to true...
go main here start...
go main here mid...
go main here end...
go thread here end...
Flag has been set, thread exiting.
*/

Thread synchronization (using semaphores)

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

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int buffer_count = 0;

sem_t mutex; // 互斥信号量,保证 buffer_count 的原子性
sem_t empty; // 空信号量,表示 buffer 中空槽数量
sem_t full; // 满信号量,表示 buffer 中满槽数量

void* producer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        data = rand() % 100;
        sem_wait(&empty); // 等待空槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        buffer[buffer_count++] = data;
        printf("Produced: %d\n", data);
        sem_post(&mutex);
        sem_post(&full); // 释放一个满槽
        usleep(rand() % 100000); // 产生一定的延迟,模拟生产过程
    }
    return NULL;
}

void* consumer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        sem_wait(&full); // 等待满槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        data = buffer[--buffer_count];
        printf("Consumed: %d\n", data);
        sem_post(&mutex);
        sem_post(&empty); // 释放一个空槽
        usleep(rand() % 100000); // 消费过程中也产生一定的延迟
    }
    return NULL;
}

int main() {
    
    
    pthread_t producer_tid, consumer_tid;
    sem_init(&mutex, 0, 1); // 初始化互斥信号量为 1
    sem_init(&empty, 0, BUFFER_SIZE); // 初始化空信号量为 BUFFER_SIZE
    sem_init(&full, 0, 0); // 初始化满信号量为 0
    pthread_create(&producer_tid, NULL, producer, NULL);
    pthread_create(&consumer_tid, NULL, consumer, NULL);
    pthread_join(producer_tid, NULL);
    pthread_join(consumer_tid, NULL);
    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    return 0;
}
/*
代码可能的执行结果:(里面用到rand(),回来的数是随机的)
Produced: 83
Consumed: 83
Produced: 15
Produced: 35
Consumed: 35
Consumed: 15
Produced: 21
Produced: 27
Consumed: 27
Consumed: 21
Produced: 26
Consumed: 26
Produced: 72
Consumed: 72
Produced: 68
Produced: 29
Consumed: 29
Consumed: 68
Produced: 23
Consumed: 23
Produced: 29
Consumed: 29
Produced: 58
Consumed: 58
Produced: 93
Produced: 11
Consumed: 11
Produced: 73
Consumed: 73
Produced: 84
Consumed: 84
Consumed: 93
Produced: 15
Produced: 13
Produced: 91
Consumed: 91
Consumed: 13
Produced: 62
Consumed: 62
Consumed: 15
*/

Guess you like

Origin blog.csdn.net/weixin_45767368/article/details/129279171