同步是指协调多个执行线程或进程的执行,以确保它们按照一定的顺序执行或在特定的条件下等待。常见的同步机制包括信号量、条件变量和屏障等。
sem_init
、sem_wait
和 sem_post
等函数进行操作。pthread_cond_init
、pthread_cond_wait
和 pthread_cond_signal
等函数进行操作。互斥是一种用于确保共享资源互斥访问的机制。在多线程或多进程环境中,互斥锁是最常见的互斥机制。
pthread_mutex_init
、pthread_mutex_lock
和 pthread_mutex_unlock
等函数进行操作。它们允许线程安全地进入和退出临界区。spin_lock
和 spin_unlock
进行操作。以上是在 Linux 中实现同步和互斥的一些常见机制。具体的选择取决于应用的需求,以及对性能和可维护性的权衡。
在下面的示例代码中,我将展示使用互斥锁(Mutex)和条件变量(Condition Variable)来实现简单的同步机制。这里使用了 POSIX 线程库的相关函数。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
void *producer(void *arg) {
for (int i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
while (count == BUFFER_SIZE) {
// 缓冲区满,等待消费者消费
pthread_cond_wait(&cond_producer, &mutex);
}
buffer[count++] = i;
printf("Produced: %d\n", i);
// 通知消费者可以消费了
pthread_cond_signal(&cond_consumer);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
for (int i = 0; i < 10; ++i) {
pthread_mutex_lock(&mutex);
while (count == 0) {
// 缓冲区空,等待生产者生产
pthread_cond_wait(&cond_consumer, &mutex);
}
int item = buffer[--count];
printf("Consumed: %d\n", item);
// 通知生产者可以生产了
pthread_cond_signal(&cond_producer);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
pthread_t producer_thread, consumer_thread;
// 创建生产者和消费者线程
pthread_create(&producer_thread, NULL, producer, NULL);
pthread_create(&consumer_thread, NULL, consumer, NULL);
// 等待线程结束
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond_producer);
pthread_cond_destroy(&cond_consumer);
return 0;
}
这个简单的示例演示了一个生产者-消费者问题,其中生产者线程负责往缓冲区中生产数据,而消费者线程负责从缓冲区中消费数据。互斥锁 mutex
用于确保对共享资源的互斥访问,而条件变量 cond_producer
和 cond_consumer
用于在缓冲区满或空时进行等待和通知。
请注意,实际应用中的同步和互斥可能更加复杂,具体的设计取决于应用的需求。
下面是一个简单的示例代码,演示了如何使用 Linux 中的 pthread_mutex_t
来实现互斥锁。这个示例中,两个线程共享一个计数器,通过互斥锁确保对计数器的互斥访问。
#include <stdio.h>
#include <pthread.h>
// 共享的计数器
int counter = 0;
// 互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 线程函数,增加计数器的值
void* increment_counter(void* arg) {
for (int i = 0; i < 100000; ++i) {
// 上锁
pthread_mutex_lock(&mutex);
// 访问共享资源
counter++;
// 解锁
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
int main() {
// 创建两个线程
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, increment_counter, NULL);
pthread_create(&thread2, NULL, increment_counter, NULL);
// 等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
// 输出最终的计数器值
printf("Final Counter Value: %d\n", counter);
return 0;
}
在这个例子中,两个线程并发地增加 counter
变量的值。由于两个线程共享同一个变量,存在竞争条件。互斥锁 mutex
用来确保对 counter
的互斥访问,一个线程在访问 counter
时先上锁,完成后再解锁,这样另一个线程才能进入。
要使用互斥锁,需要注意以下几点:
PTHREAD_MUTEX_INITIALIZER
或者 pthread_mutex_init
来初始化互斥锁。pthread_mutex_lock
来上锁,使用 pthread_mutex_unlock
来解锁。在临界区内对共享资源的访问应该位于上锁和解锁之间。pthread_mutex_destroy
来销毁它。以上代码演示了如何使用互斥锁来确保对共享资源的安全访问,防止竞争条件。