在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); // 初始化信号量,初始值为1pthread_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;
}