时间:2023-05-29 来源:网络 人气:
在多核时代,多线程编程已成为程序员必备技能之一。但是,多线程编程也带来了许多问题,其中最重要的就是线程同步和互斥。为了解决这些问题,我们需要使用一些同步机制,例如信号量、互斥量、条件变量等。本文将介绍如何使用这些同步机制来保证线程的同步和互斥。
一、信号量
信号量是一种经典的同步机制。它可以用于控制对共享资源的访问,从而实现线程间的同步和互斥。信号量有两种类型:二进制信号量和计数信号量。
二进制信号量只有两个状态:0和1。它可以用于表示一个共享资源是否正在被占用。当二进制信号量的值为1时,表示共享资源未被占用;当值为0时,表示共享资源正在被占用。
计数信号量可以表示一个共享资源可用的数量。当计数信号量的值为N时,表示共享资源可用N次。每次访问共享资源时,需要将计数信号量的值减1;当访问完成后,需要将计数信号量的值加1。如果计数信号量的值为0,则表示共享资源已经被占用,需要等待其他线程释放共享资源。
下面是一个使用信号量实现线程同步和互斥的例子:
c
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#defineNTHREADS10
sem_tsem;
void*thread_func(void*arg){
intid=(int)arg;
printf("Thread%d:beforecriticalsection\n",id);
sem_wait(&sem);
printf("Thread%d:insidecriticalsection\n",id);
sleep(1);
printf("Thread%d:aftercriticalsection\n",id);
sem_post(&sem);
returnNULL;
}
intmain(){
pthread_tthreads[NTHREADS];
sem_init(&sem,0,1);
for(inti=0;i<NTHREADS;i++){
pthread_create(&threads[i],NULL,thread_func,(void*)i);
}
for(inti=0;i<NTHREADS;i++){
pthread_join(threads[i],NULL);
}
sem_destroy(&sem);
return0;
}
上面的代码创建了10个线程,每个线程都会访问一个共享资源。在访问共享资源之前,线程会调用`sem_wait`函数等待信号量;在访问完成后,线程会调用`sem_post`函数释放信号量。这样可以保证同时只有一个线程访问共享资源。
二、互斥量
互斥量是一种用于保护共享资源的同步机制。它可以用于控制对共享资源的访问,从而实现线程间的互斥。互斥量有两种状态:锁定和非锁定。
当一个线程需要访问共享资源时,它会先尝试获取互斥量的锁。如果互斥量当前处于非锁定状态,则线程会成功获取锁,并执行临界区代码;如果互斥量当前处于锁定状态,则线程会被阻塞,直到互斥量被解锁为止。
下面是一个使用互斥量实现线程同步和互斥的例子:
c
#include<stdio.h>
#include<pthread.h>
#defineNTHREADS10
pthread_mutex_tmutex;
void*thread_func(void*arg){
intid=(int)arg;
printf("Thread%d:beforecriticalsection\n",id);
pthread_mutex_lock(&mutex);
printf("Thread%d:insidecriticalsection\n",id);
sleep(1);
printf("Thread%d:aftercriticalsection\n",id);
pthread_mutex_unlock(&mutex);
returnNULL;
}
intmain(){
pthread_tthreads[NTHREADS];
pthread_mutex_init(&mutex,NULL);
for(inti=0;i<NTHREADS;i++){
pthread_create(&threads[i],NULL,thread_func,(void*)i);
}
for(inti=0;i<NTHREADS;i++){
pthread_join(threads[i],NULL);
}
pthread_mutex_destroy(&mutex);
return0;
}
上面的代码与前面的例子类似,但使用了互斥量来保护共享资源。在访问共享资源之前,线程会调用`pthread_mutex_lock`函数获取互斥量的锁;在访问完成后,线程会调用`pthread_mutex_unlock`函数释放互斥量的锁。这样可以保证同时只有一个线程访问共享资源。
三、条件变量
条件变量是一种用于在线程间传递信号和数据的同步机制。它可以用于解决生产者消费者问题、读写者问题等。
条件变量需要与互斥量配合使用。当一个线程需要等待某个条件成立时,它会先释放互斥量,并等待条件变量的信号;当条件成立时,另一个线程会发送信号给条件变量,唤醒等待该条件变量的线程。
下面是一个使用条件变量实现生产者消费者问题的例子:
c
#include<stdio.h>
#include<pthread.h>
#defineBUFFER_SIZE10
intbuffer[BUFFER_SIZE];
intcount=0;
pthread_mutex_tmutex;
pthread_cond_tcond;
void*producer(void*arg){
for(inti=0;i<100;i++){
pthread_mutex_lock(&mutex);
while(count==BUFFER_SIZE){
pthread_cond_wait(&cond,&mutex);
}
buffer[count++]=i;
printf("Producer:produced%d\n",i);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
returnNULL;
}
void*consumer(void*arg){
for(inti=0;i<100;i++){
pthread_mutex_lock(&mutex);
while(count==0){
pthread_cond_wait(&cond,&mutex);
}
intvalue=buffer[--count];
printf("Consumer:consumed%d\n",value);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
returnNULL;
}
intmain(){
pthread_tproducer_thread,consumer_thread;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
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);
return0;
}
上面的代码创建了一个生产者线程和一个消费者线程,它们共享一个缓冲区。当缓冲区为空时,消费者线程会等待生产者线程生产数据;当缓冲区已满时,生产者线程会等待消费者线程消费数据。这样可以保证生产者和消费者之间的同步。
结论
本文介绍了如何使用信号量、互斥量和条件变量来保证线程的同步和互斥。这些同步机制可以用于控制对共享资源的访问,从而避免出现竞态条件和死锁等问题。在实际编程中,需要根据具体情况选择合适的同步机制,并注意避免常见的同步问题,例如饥饿、死锁等。
imtoken钱包:https://cjge-manuscriptcentral.com/software/4776.html