C语言实现线程间通信的几种方式
线程间通信是多线程编程中的一个基本议题。线程间通信在多线程编程实践中非常重要,也是多线程编程中的一个基础知识。可以通过多种方式实现线程间通信,本文将介绍C语言中的几种常用方式。
信号量
信号量是一种同步机制,用于控制对共享资源的访问。在C语言中,使用信号量可以实现线程间的同步和互斥。通过使用信号量,可以确保一次只有一个线程访问资源,而其他线程则被阻塞,直到占用资源的线程释放它。信号量的实现依赖于系统,一般情况下,在Linux和Windows操作系统中都提供了信号量的支持。
下面是一个使用信号量实现线程间同步的例子:
```
#include
#include
#include
#include
#defineMAX_THREAD_NUM5
#defineWORK_TIMES5
intg_count=0;
sem_tsem;
void*thread_func(void*arg)
{
inti;
for(i=0;i在上面的例子中,使用信号量sem来控制对全局变量g_count的访问,每个线程执行一定次数的工作,并对g_count进行更新。由于信号量的初始值为1,所以第一个访问g_count的线程不会被阻塞,其他线程则一次只能有一个线程访问g_count。在每个线程对g_count进行修改之前,使用sem_wait函数对sem进行P操作,从而实现互斥访问。在修改完成之后,使用sem_post函数对sem进行V操作,唤醒其他被阻塞的线程。
条件变量
条件变量是一种同步机制,用于线程间通信。在C语言中,使用条件变量可以灵活的实现生产者-消费者模型、读写者模型等场景。当某个条件不满足时,线程可以通过条件变量等待,等待相应的条件满足后再被唤醒。条件变量的实现依赖于系统,一般情况下,在Linux和Windows操作系统中都提供了条件变量的支持。
下面是一个使用条件变量实现生产者-消费者模型的例子:
```
#include
#include
#include
#defineBUFFER_SIZE10
#defineMAX_ITEM_NUM100
intg_buffer[BUFFER_SIZE];
intg_front=0,g_rear=0;
intg_item_count=0;
pthread_mutex_tmutex;
pthread_cond_tcond;
void*producer_func(void*arg)
{
intitem=0;
while(1)
{
pthread_mutex_lock(&mutex);
if(g_item_count==MAX_ITEM_NUM)
{
pthread_cond_wait(&cond,&mutex);
}
item++;
g_buffer[g_rear]=item;
g_rear=(g_rear+1)%BUFFER_SIZE;
g_item_count++;
printf(\"producerproduceditem%d,count=%d\
\",item,g_item_count);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(1);
}
pthread_exit(NULL);
}
void*consumer_func(void*arg)
{
intitem;
while(1)
{
pthread_mutex_lock(&mutex);
if(g_item_count==0)
{
pthread_cond_wait(&cond,&mutex);
}
item=g_buffer[g_front];
g_front=(g_front+1)%BUFFER_SIZE;
g_item_count--;
printf(\"consumerconsumeditem%d,count=%d\
\",item,g_item_count);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(1);
}
pthread_exit(NULL);
}
intmain(intargc,char*argv[])
{
pthread_tproducer_thread,consumer_thread;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_create(&producer_thread,NULL,producer_func,NULL);
pthread_create(&consumer_thread,NULL,consumer_func,NULL);
pthread_join(producer_thread,NULL);
pthread_join(consumer_thread,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return0;
}
```
在上面的例子中,使用条件变量cond实现了一个生产者-消费者模型。生产者线程负责生产数据,消费者线程负责消费数据。多个生产者和消费者线程可以同时进行工作,而使用条件变量即可得到正确的结果。在生产者的生产之前,如果缓冲区已满,则使用pthread_cond_wait函数等待条件变量cond。当消费者消费掉一些数据后,即释放了一些缓存空间,生产者线程又可以从前面的条件变量处返回,继续进行生产。每当生产者线程生产一个数据后,都会使用pthread_cond_signal函数唤醒消费者线程,消费者在消费一个数据之后,也会进行相同的操作,在消费完一个数据之后,唤醒生产者线程。
管道
管道是一种基本的进程间通信方式。在C语言中,使用管道(pipe)可以实现父进程和子进程之间的通信,也可以用于线程间通信。在管道中,一个进程向管道写入数据,另一个进程从管道读取数据。管道具有缓冲的能力,当数据流进来时缓冲区满了,会暂停写入数据,缓冲区空闲时又可以继续写入数据。在管道中,父进程和子进程只能单向的进行数据通信,无法进行双向通信。
下面是一个使用管道进行线程间通信的例子:
```
#include
#include
#include
#include
#defineBUFFER_SIZE1024
intg_fd[2];
void*write_thread(void*arg)
{
charbuffer[BUFFER_SIZE];
inti=0;
for(i=0;i<5;i++)
{
sprintf(buffer,\"message%dfromwrite_thread\
\",i+1);
write(g_fd[1],buffer,sizeof(buffer));
sleep(1);
}
pthread_exit(NULL);
}
void*read_thread(void*arg)
{
charbuffer[BUFFER_SIZE];
intnbytes;
while(1)
{
nbytes=read(g_fd[0],buffer,sizeof(buffer));
if(nbytes==0)
{
break;
}
printf(\"%s\",buffer);
}
pthread_exit(NULL);
}
intmain(intargc,char*argv[])
{
pthread_twrite_tid,read_tid;
if(pipe(g_fd)<0)
{
printf(\"pipeerror!\
\");
return0;
}
pthread_create(&write_tid,NULL,write_thread,NULL);
pthread_create(&read_tid,NULL,read_thread,NULL);
pthread_join(write_tid,NULL);
close(g_fd[1]);
pthread_join(read_tid,NULL);
close(g_fd[0]);
return0;
}
```
上面的例子中创建了一个管道g_fd,该管道的读写文件描述符分别为g_fd[0]和g_fd[1]。在写线程中,将一些数据写入管道中,而在读线程中,从管道中读取数据。在主线程中,使用函数close函数关闭了读写文件描述符,最终等待读线程结束。
以上三种方法都是很好的线程间通信的方式,具体的使用场景根据不同的情况可以选择采用不同的方式。