在Linux下,线程同步是保证多个线程在共享资源时,不会发生数据冲突或资源不一致的关键技术。以下是Linux下常用的几种线程同步方法,以及每种方法的简要解释和示例代码。
1. 互斥锁 (Mutex)
互斥锁是一种最基本的同步机制,它确保在任意时刻,只有一个线程可以访问共享资源。
示例代码:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t lock; // 定义互斥锁
int shared_resource = 0;
void* increment(void* arg) {
pthread_mutex_lock(&lock); // 加锁
shared_resource++;
printf("Shared Resource: %d\n", shared_resource);
pthread_mutex_unlock(&lock); // 解锁
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL); // 初始化互斥锁
pthread_create(&t1, NULL, increment, NULL);
pthread_create(&t2, NULL, increment, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock); // 销毁互斥锁
return 0;
}
2. 读写锁 (Read-Write Lock)
读写锁允许多个线程同时读取共享资源,但在写入时,其他线程不能读取或写入。
示例代码:
#include <pthread.h>
#include <stdio.h>
pthread_rwlock_t rwlock;
int shared_resource = 0;
void* reader(void* arg) {
pthread_rwlock_rdlock(&rwlock); // 加读锁
printf("Reader: %d\n", shared_resource);
pthread_rwlock_unlock(&rwlock); // 解锁
return NULL;
}
void* writer(void* arg) {
pthread_rwlock_wrlock(&rwlock); // 加写锁
shared_resource++;
printf("Writer: %d\n", shared_resource);
pthread_rwlock_unlock(&rwlock); // 解锁
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_rwlock_init(&rwlock, NULL); // 初始化读写锁
pthread_create(&t1, NULL, reader, NULL);
pthread_create(&t2, NULL, writer, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_rwlock_destroy(&rwlock); // 销毁读写锁
return 0;
}
3. 信号量 (Semaphore)
信号量是一种用于控制多个线程对共享资源访问的计数器,特别适用于控制一定数量的资源。
示例代码:
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
sem_t semaphore;
int shared_resource = 0;
void* worker(void* arg) {
sem_wait(&semaphore); // 等待信号量
shared_resource++;
printf("Shared Resource: %d\n", shared_resource);
sem_post(&semaphore); // 释放信号量
return NULL;
}
int main() {
pthread_t t1, t2;
sem_init(&semaphore, 0, 1); // 初始化信号量,初始值为1
pthread_create(&t1, NULL, worker, NULL);
pthread_create(&t2, NULL, worker, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
sem_destroy(&semaphore); // 销毁信号量
return 0;
}
4. 条件变量 (Condition Variable)
条件变量让线程在满足某个条件时等待或唤醒其他线程,常与互斥锁结合使用。
示例代码:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t lock;
pthread_cond_t cond;
int ready = 0;
void* wait_for_signal(void* arg) {
pthread_mutex_lock(&lock);
while (!ready) {
pthread_cond_wait(&cond, &lock); // 等待条件变量
}
printf("Signal received!\n");
pthread_mutex_unlock(&lock);
return NULL;
}
void* send_signal(void* arg) {
pthread_mutex_lock(&lock);
ready = 1;
pthread_cond_signal(&cond); // 发送信号
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&t1, NULL, wait_for_signal, NULL);
pthread_create(&t2, NULL, send_signal, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
以上是几种常见的Linux线程同步方法,每种方法都有其适用的场景。选择合适的同步机制,能够有效防止竞争条件,保证多线程程序的正确性和稳定性。
5. 屏障(Barrier)
屏障用于阻止一组线程中的任何一个继续执行,直到所有线程都到达屏障点。
- 使用场景:当多个线程需要在某个点进行同步,并确保所有线程都到达某个状态后再继续执行时。
- 示例:
#include <pthread.h>
pthread_barrier_t barrier;
void* thread_function(void* arg) {
// 到达屏障点
pthread_barrier_wait(&barrier);
// 所有线程都到达屏障点后继续执行
return nullptr;
}
int main() {
pthread_barrier_init(&barrier, NULL, 5); // 5 表示需要同步的线程数
// 创建线程并使用屏障同步
pthread_barrier_destroy(&barrier);
return 0;
}
6. 自旋锁(Spinlock)
自旋锁是一种忙等待锁,当一个线程尝试获取锁时,如果锁已经被其他线程占用,它会一直循环检查锁的状态,而不是进入休眠状态。
- 使用场景:在锁的持有时间非常短的情况下,使用自旋锁可以避免线程调度的开销。
- 示例:
#include <pthread.h>
pthread_spinlock_t spinlock;
void* thread_function(void* arg) {
pthread_spin_lock(&spinlock);
// 临界区代码
pthread_spin_unlock(&spinlock);
return nullptr;
}
int main() {
pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);
// 创建线程并使用自旋锁同步
pthread_spin_destroy(&spinlock);
return 0;
}
7. 文件锁(File Locking)
文件锁用于多个进程或线程间同步访问文件。flock
和 fcntl
是两种常用的文件锁定方法。
- 使用场景:多个线程或进程需要同步访问文件资源时。
- 示例(使用
flock
):
#include <sys/file.h>
#include <unistd.h>
#include <fcntl.h>
void lock_file(int fd) {
flock(fd, LOCK_EX); // 独占锁
// 文件操作
flock(fd, LOCK_UN); // 解锁
}
int main() {
int fd = open("file.txt", O_RDWR);
lock_file(fd);
close(fd);
return 0;
}