以下是关于 POSIX线程库(pthread) 的核心知识点总结,涵盖线程管理、同步机制及常见面试问题:
一、线程基础
1. 线程创建与终止
-
创建线程:
pthread_createint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);thread:存储新线程的ID。attr:线程属性(默认用NULL)。start_routine:线程函数(返回void*,参数void*)。arg:传递给线程函数的参数。
示例:
void* print_hello(void *arg) { printf("Hello from thread!\n"); return NULL; } pthread_t tid; pthread_create(&tid, NULL, print_hello, NULL); -
终止线程:
- 线程函数返回(隐式终止)。
- 显式调用
pthread_exit(void *retval)。 - 主线程调用
exit()会终止整个进程(包括所有线程)。
2. 等待线程结束:pthread_join
int pthread_join(pthread_t thread, void **retval);
- 阻塞当前线程,直到目标线程结束。
retval:接收线程的返回值(需通过pthread_exit或return传递)。
示例:
void* thread_func(void *arg) {
int *num = (int*)arg;
*num *= 2;
return (void*)num;
}
int main() {
int val = 42;
pthread_t tid;
pthread_create(&tid, NULL, thread_func, &val);
int *result;
pthread_join(tid, (void**)&result);
printf("Result: %d\n", *result); // 输出 84
}
二、线程同步机制
1. 互斥锁(Mutex)
-
初始化与销毁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态初始化 // 或动态初始化 pthread_mutex_init(&mutex, NULL); pthread_mutex_destroy(&mutex); -
加锁与解锁:
pthread_mutex_lock(&mutex); // 阻塞直到获取锁 // 临界区代码 pthread_mutex_unlock(&mutex);示例(线程安全的计数器):
int counter = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void* increment(void *arg) { for (int i = 0; i < 1000; i++) { pthread_mutex_lock(&mutex); counter++; pthread_mutex_unlock(&mutex); } return NULL; }
2. 条件变量(Condition Variables)
-
初始化与销毁:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_cond_init(&cond, NULL); pthread_cond_destroy(&cond); -
等待与通知:
// 等待条件(需配合互斥锁) pthread_cond_wait(&cond, &mutex); // 唤醒一个等待线程 pthread_cond_signal(&cond); // 唤醒所有等待线程 pthread_cond_broadcast(&cond);示例(生产者-消费者模型):
int buffer = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void* producer(void *arg) { pthread_mutex_lock(&mutex); buffer = 1; pthread_cond_signal(&cond); // 通知消费者 pthread_mutex_unlock(&mutex); return NULL; } void* consumer(void *arg) { pthread_mutex_lock(&mutex); while (buffer == 0) { pthread_cond_wait(&cond, &mutex); // 释放锁并等待 } printf("Consumed: %d\n", buffer); pthread_mutex_unlock(&mutex); return NULL; }
3. 读写锁(Read-Write Lock)
- 适用场景:读操作频繁,写操作较少。
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; pthread_rwlock_rdlock(&rwlock); // 读锁 pthread_rwlock_wrlock(&rwlock); // 写锁 pthread_rwlock_unlock(&rwlock);
4. 自旋锁(Spinlock)
- 特点:忙等(不释放CPU),适用于锁持有时间短的场景。
pthread_spinlock_t spinlock; pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE); pthread_spin_lock(&spinlock); pthread_spin_unlock(&spinlock);
三、线程属性
- 设置线程属性(如分离状态、栈大小):
pthread_attr_t attr; pthread_attr_init(&attr); // 设置线程为分离状态(无需pthread_join) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&tid, &attr, thread_func, NULL); pthread_attr_destroy(&attr);
四、线程局部存储(Thread-Local Storage, TLS)
- 用途:每个线程拥有独立的变量副本。
pthread_key_t key; pthread_key_create(&key, NULL); // 第二个参数是析构函数 // 设置线程局部变量 pthread_setspecific(key, (void*)value); // 获取线程局部变量 void* value = pthread_getspecific(key);
五、常见面试问题
-
线程 vs 进程的区别
- 线程共享进程的内存空间,进程拥有独立的内存空间。
- 线程切换开销小,进程切换开销大。
-
死锁的四个必要条件
- 互斥条件、占有且等待、不可抢占、循环等待。
-
如何避免死锁
- 按固定顺序加锁。
- 使用超时锁(如
pthread_mutex_trylock)。
-
竞争条件(Race Condition)
- 多个线程同时访问共享资源且未同步,导致结果不确定性。
六、综合示例(多线程计算数组和)
#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 4
#define ARRAY_SIZE 1000
int array[ARRAY_SIZE];
int partial_sums[NUM_THREADS] = {0};
void* sum_array(void *arg) {
int thread_id = *(int*)arg;
int start = thread_id * (ARRAY_SIZE / NUM_THREADS);
int end = start + (ARRAY_SIZE / NUM_THREADS);
for (int i = start; i < end; i++) {
partial_sums[thread_id] += array[i];
}
return NULL;
}
int main() {
// 初始化数组
for (int i = 0; i < ARRAY_SIZE; i++) array[i] = i + 1;
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
// 创建线程
for (int i = 0; i < NUM_THREADS; i++) {
thread_ids[i] = i;
pthread_create(&threads[i], NULL, sum_array, &thread_ids[i]);
}
// 等待线程结束
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
// 汇总结果
int total = 0;
for (int i = 0; i < NUM_THREADS; i++) {
total += partial_sums[i];
}
printf("Total sum: %d\n", total); // 应输出 500500
return 0;
}
七、注意事项
- 编译时链接pthread库:
gcc program.c -o program -lpthread - 避免内存泄漏:确保销毁动态初始化的锁和条件变量。
- 线程安全函数:确保调用的库函数是线程安全的(如
rand_r替代rand)。

2130

被折叠的 条评论
为什么被折叠?



