个人总结,请各位审慎的,批判着看。
当两个线程访问共享数据时,可以用互斥锁来进行同步。先看一个例子:
该程序有两个线程,一个用来从键盘读取输入的数据,一个把读取的数据显示出来。其中,数组buffer为两个线程的共享数据。
编译:gcc mutex_pthread.c -lpthread,不要忘记-lpthread。
运行该程序,在键盘上输入数据,然后把数据显示出来。读一个,写一个,如此循环。代码如下:
/* mutex_pthread.c*/
#include
#include
char buffer[128];
int buffer_has_data=0;//0:数据为空,可以写数据;1:数据不为空,可以读取数据。
pthread_mutex_t mutex;//锁定标志
/*从键盘读取数据,并存储到buffer中*/
void write_buffer(char *data)
{
pthread_mutex_lock(&mutex);
/* 尝试加锁,如果该互斥锁已经被锁定了,则该函数将会阻塞,卡住不动,除非解锁,才会继续往下执行*/
if(buffer_has_data==0)//判断数据是否被读取了
{
sprintf(buffer,"%s",data); //如果数据已经被读取,则写入新的数据
buffer_has_data=1;
}
pthread_mutex_unlock(&mutex);//解锁
}
/*把buffer中的数据显示到屏幕中*/
void read_buffer(void)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(buffer_has_data==1)
{
printf("read buffer,data = %s\n\n",buffer);
buffer_has_data=0;
}
pthread_mutex_unlock(&mutex);
printf("子线程先运行,但是没有数据可读就解锁了\n");
sleep(1);//该程序的不足之处
}
}
int main(int argc, char **argv)
{
char input[128];
pthread_t reader;
pthread_mutex_init(&mutex,NULL);//生成互斥锁mutex,用默认属性初始化一个互斥锁对象
pthread_create(&reader,NULL,(void*)(read_buffer),NULL);//新建线程
while(1)
{
scanf("%s",input);//从键盘获得数据
write_buffer(input);
}
pthread_join(reader,NULL);
pthread_mutex_destroy(&mutex);//释放互斥锁mutex资源
return 0;
}
执行完pthread_create(&reader,NULL,(void*)(read_buffer),NULL);之后,read_buffer()首先加锁。由于buffer_has_data=0,没有数据可读,该线程解锁。如果没有数据可读,则该线程一直不停的加锁,解锁。
主线程执行完write_buffer(input);之后,也尝试加锁。待抢到锁之后,向buffer中写入数据,更新buffer_has_data的值,并释放锁,然后阻塞在scanf("%s",input);处,等待写入新的数据。
这样,就能够对共享数据buffer进行精确的控制,保证写一次,读一次。
该程序的缺陷:在read_buffer()中,需要不停的尝试加锁。
如果注释掉sleep(1),当buffer中没有数据可读时,则该线程不停的加锁,解锁,一直循环,占用太多CPU资源。测试时发现,CPU利用率飙升的很高,这在实际应用中是不允许的。
如果不注释掉sleep(1),则程序会有一个延时,实时性降低,也就是说CPU的利用率和时效性不可兼得。
既然该程序的实时性较差,那么它是否一无是处呢?答案是否定的。在一些对实时性要求不高的场合,比如对温度的采集,可以使用该程序。
如何使程序不占用太多的CPU资源,又能获得较高的实时性呢,我们可以使用条件变量。
欲知条件变量为何物,请听下文分解。