Article directory
-
-
- brief description
- method
-
- pthread_t
- pthread_create()
- pthread_join()
- pthread_exit()
- pthread_mutex_t
- pthread_mutex_init()
- pthread_mutex_lock()
- pthread_mutex_unlock()
- pthread_mutex_destroy()
- pthread_cond_t
- pthread_cond_init()
- pthread_cond_wait()
- pthread_cond_signal()
- pthread_cond_broadcast()
- pthread_cond_destroy()
- sem_t
- sem_init()
- sem_wait()
- sem_post()
- sem_destroy()
- pthread_key_t
- pthread_key_create()
- pthread_setspecific()
- pthread_getspecific()
- pthread_key_delete()
- pthread_once_t
- pthread_key_delete()
- example
-
brief description
POSIX
A thread (Pthreads)
is a standard multithreading API
that provides a set of functions and data types that enable programmers to use multiple threads to perform tasks concurrently. POSIX
Thread support Unix
runs on class operating systems and is cross-platform.
method
The following are some commonly used POSIX
thread 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 threadID
, if the thread is created successfully, it will be filled as the new threadID
.attr
: Used to set the properties of the new thread, if passed inNULL
, 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 threadarg
: is the parameter passed tostart_routine
the function
When pthread_create()
the function , a new thread is created and the new thread executes start_routine
the function. If start_routine
the 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_routine
the 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 onID
.retval
: The return value of the thread, which can beNULL
.
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_INITIALIZER
for 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 beNULL
.
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_t
Variables 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 be0
or1
.pshared
When the value0
of is , it means that the semaphore can only be shared among multiple threads of the current process; whenpshared
the value1
of 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 of1
indicates that only one resource is available, and an initial value of0
indicates 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 topthread_key_t
the type used to store the key of the created thread private datadestructor
: 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 setdestructor
the parameter toNULL
.- 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
POSIX
A 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 volatile
a int
type 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_t
The initialization of variables should use PTHREAD_ONCE_INIT
the macro , which is defined pthread.h
in the header file, and its definition is as follows:
#define PTHREAD_ONCE_INIT 0
It should be noted that pthread_once_t
the 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
*/