首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

linux多线程编程之同步与互斥实例讲解

linux多线程编程之同步与互斥实例讲解

一、 为什么要用多线程技术?

1.       避免阻塞,大家知道,单个进程只有一个主线程,当主线程阻塞的时候,整个进程也就阻塞了,无法再去做其它的一些功能了。

2.       避免CPU空转,应用程序经常会涉及到RPC,数据库访问,磁盘IO等操作,这些操作的速度比CPU慢很多,而在等待这些响应时,CPU却不能去处理新的请求,导致这种单线程的应用程序性能很差。

3.       提升效率,一个进程要独立拥有4GB的虚拟地址空间,而多个线程可以共享同一地址空间,线程的切换比进程的切换要快得多。


二、  如何使用多线程技术进行编程?

首先给一个完整的多线程程序,以下是最简单的模拟火车票售票系统:

         #include<stdio.h>
         #include<pthread.h>

#include<errno.h>

#include<stdlib.h>

#include<unistd.h>

void* ticketport1(void*);//线程函数声明

void* ticketport2(void*);//线程函数声明

int tickets=100;                           //火车票的起始值

int main()

{

         pthread_t id1,id2;

         int ret;

         ret=pthread_create(&id1,NULL,ticketport1,NULL);       //创建线程1

         if(ret<0)

         {

                   perror("creat thread1:");

                   exit(-1);

         }

         ret=pthread_create(&id2,NULL,ticketport2,NULL);       //创建线程2

         if(ret<0)

         {

                   perror("creat thread2:");

                   exit(-1);

         }

         pthread_join(id1,NULL);                    //等待线程1结束

         pthread_join(id2,NULL);                    //等待线程2结束

         return  0;

}


void* ticketport1(void* arg)

{

         while(1)

         {

                   if(tickets>0)

                   {

                            //usleep(1000);

                            //售票点1每卖一张票,自减一

                            printf("ticketport1 sells ticket: %d\n",tickets--);   

                   }

                   else

                   {

                            break;

                   }

         }

         return (void*)0;

}


void* ticketport2(void* arg)

{

         while(1)

         {

                   if(tickets>0)

                   {

                            //usleep(1000);

                            //售票点2每卖一张票,自减一

                            printf("ticketport2 sells ticket: %d\n",tickets--);

                   }

                   else

                   {

                            break;

                   }

         }

         return (void*)0;

}

我们用pthread_create函数来创建线程,用pthread_join来阻塞主线程,等待子线程执行完成后返回。利用了多线程技术来创建了两个售票点,可以不同的地方进行同时售票。
用gcc带选项-lpthread来连结pthread库函数。执行这个程序发现两个售票点在正常售票,一部分连续是ticketport1,另一部分连续是ticketport2;此时,其实存在一个隐含的问题,就是线程间的切换,在单CPU系统中,CPU是有时间片时间,时间片到了,就要执行其它的线程,假设thread1执行到if里面,但在printf执行前发生了线程切换,那么会发生什么呢?我们在这里用usleep函数(放开程序中的usleep注释行)进行强制模拟切换,编译运行程序发现竟然有0号票被卖出了,这显然是错误的!当thread1的if里面发生线程切换时,thread2得到运行,把最后一张票卖了,此时thread1恢复运行,结果卖出了0号票,这里我们需要的是火车票的票数数据对于所有线程而言是同步的,所以就要用到线程同步技术了。

三、  使用多线程的同步与互斥

1、多线程的同步方式有很多种,例如互斥锁,条件变量,信号量,读写锁。先看看互斥锁如何解决多线程之间的同步问题。程序用互斥锁后如下:

#include<stdio.h>

#include<pthread.h>

#include<errno.h>

#include<stdlib.h>

#include<unistd.h>

void* ticketport1(void*);

void* ticketport2(void*);

int tickets=100;

pthread_mutex_t mutex;                 

int main()

{

         int ret;

         pthread_t id1,id2;

         pthread_mutex_init(&mutex,NULL);                                  //初始化互斥量

         ret=pthread_create(&id1,NULL,ticketport1,NULL);

         if(ret<0)

         {

                   perror("creat thread1:");

                   exit(-1);

         }

         ret=pthread_create(&id2,NULL,ticketport2,NULL);

         if(ret<0)

         {

                   perror("creat thread2:");

                   exit(-1);

         }

         pthread_join(id1,NULL);

         pthread_join(id2,NULL);

}


void* ticketport1(void* arg)

{

         while(1)

         {

                   pthread_mutex_lock(&mutex);                //给互斥量上锁

                   if(tickets>0)

                   {

                            usleep(1000);

                            printf("thread1 sell ticket: %d\n",tickets--);

                            pthread_mutex_unlock(&mutex);            //给互斥量解锁

                   }

                   else

                   {

                            pthread_mutex_unlock(&mutex);            //给互斥量解锁

                            break;

                   }

                   pthread_yield();                 //线程的调度函数,使两个线程都有执行机会

         }

         return (void*)0;

}


void* ticketport2(void* arg)

{

         while(1)

         {

                   pthread_mutex_lock(&mutex);                //给互斥量上锁

                   if(tickets>0)

                   {  

                            usleep(1000);

                            printf("thread2 sell ticket: %d\n",tickets--);

                            pthread_mutex_unlock(&mutex);            //给互斥量解锁

                   }

                   else

                   {

                            pthread_mutex_unlock(&mutex);            //给互斥量解锁

                            break;

                   }

                   pthread_yield();                //线程的调度函数,使两个线程都有执行机会

         }

         return (void*)0;

}

我们用pthread_mutext_init函数来初始化互斥量,然后再用pthread_mutex_lock函数和pthread_mutext_unlock分别进行上锁和解锁,至于这两个函数的参数说明,大家可以上网查阅,在这我只说明功能。我们用gcc带选项-lpthread编译后多次执行发现即使强制线程在很短的时间内(如1ms)睡眠引起线程切换,也不会导致上述的问题,说明互斥锁可以解决线程间的同步问题。

继承事业,薪火相传
返回列表