APP下载

浅谈linux多线程协作

2017-03-09史欢欢周光森姚永哲

环球市场 2017年36期
关键词:调用线程队列

史欢欢 周光森 姚永哲

沈阳中钞信达金融设备有限公司

1、线程的创建和终止

1)在线程创建之前,需要初始化线程,设置线程的优先级、是否继承父进程优先级、调度策略,并分配各个线程的优先级。创建线程的函数是pthread_create()。

2)线程的终止的两种方式:第一通过return从线程函数返回,第二种通过调用pthread_exit()函数使线程退出。此外,主线程中如果从main函数返回或是调用了exit函数退出主线程,则整个进程终止,此时所有的其他线程也将终止。另一种是,如果主线程调用pthread_exit函数,则仅仅是主线程消亡,进程不会结束,其他线程也不会结束,直到所有的线程都结束时,进程才结束。

2、多线程协作

线程与线程之间通讯,互相交互变量,不能总用全局变量,这样会出现A线程正在改全局变量的值,B线程却在读全局变量的值,因为各线程是并行工作,所以需要加互斥锁、条件变量或消息队列来同步。

1)互斥锁pthread_mutex_lock(unlock或trylock):用来防止两个进程或线程在同一时刻访问相同的共享资源。如果互斥量已经上锁,调用线程会阻塞,直到互斥量被解锁。比如A和B两个线程都要用a变量,在A线程中,加锁之后改变a变量的值,然后解锁,而在B线程中,加锁之后读a变量的值,然后解锁,加锁和解锁必须判断是否成功,否则对a变量的读写会出错,最好用pthread_mutex_trylock加锁,如果加锁失败,会返回EBUSY,成功则返回0,返回EBUSY说明另一线程对这个变量加锁后还未解锁。此外,阻塞和非阻塞的意思是,阻塞是一直加锁直到成功,非阻塞是加锁完毕后不管成功与否都返回。

2)条件变量cond

条件变量的基本操作是当触发条件(当条件变为真时),等待条件,挂起线程直到其他线程触发条件。即A线程先进入wait等待,让其挂起,等待B线程执行激活后,A线程继续执行。为了防止竞争,条件变量总是和一个互斥锁结合在一起。pthread_cond_wait一般嵌套在while(条件)中,条件第一次满足就可以。激活等待线程是激发条件有两种形式,pthread_cond_signal( )激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。

3)消息队列:在A线程中改变某个变量后,发消息给B线程,B线程在没有得到消息时处于挂起状态,除非A线程给B线程发消息,B线程接收到消息才开始执行msgrcv的下一行代码。msgsnd向队列末端添加一条新消息;msgrcv从队列中取消息,取消息是不一定遵循先进先出的,也可以按消息的类型字段取消息;

4)线程之间是异步的,无法确定哪个线程先执行。如果在同一优先级中有N个线程,需要使用sleep来调整各个线程执行的顺序。

5)Linux下多个线程同时对一个文件进行写操作,需要使用文件锁解决冲突,使用int flock(int fd,int operation)(锁定文件或解除锁定)函数。flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。LOCK_EX 建立互斥锁定,一个文件同时只有一个互斥锁定。LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_EX 做OR(|)组合。

if(flock(fileno(文件指针),LOCK_EX | LOCK_NB)== FAILURE)//文件加锁

if(flock(fileno(文件指针),LOCK_UN)== FAILURE)//释放文件锁

3、线程内部处理

1)线程中程序不运行的三种状态睡眠sleep()、阻塞、挂起,他们的区别是:

①挂起:没有满足的运行条件,正在待命,比如msgrcv,没有接收到消息时就挂起,让别的线程执行,自己等待msgsnd,一旦接收到消息,继续执行;

②sleep( ):歇一会,让别的线程先运行;

③阻塞:线程由于等待处理器外的其他条件无法运行,如条件变量的改变、加锁互斥量或I/O操作结束。

2)单线程进入死循环

如果线程中所有程序的执行需要满足if条件,但if条件一直不满足,这个线程将处于死循环,使别的线程也无法执行。可以在if之后加入else,里面是sleep(),在执行sleep()期间,别的线程就可以运行。

3)线程定时执行

如果想让在线程定时执行某个函数,需要用到setitimer()有两个功能,一是指定一段时间后,才执行某个function,二是每间隔一段时间就执行某个function。如果要实现间隔执行,程序中一定要加pause( )函数,并且嵌套在while(1)中。

结束语:

在应用软件中编写各个线程的程序。调用linux中的系统函数一定要接收返回值来判断是否执行成功。linux程序不能实时仿真,调试程序只能通过printf打印变量值到串口。所以在写linux程序,一定要防止内存泄漏,比如数组、变量类型、指针一定要推敲使用。遇到内存泄漏,用printf来打印定位。

猜你喜欢

调用线程队列
基于C#线程实验探究
队列里的小秘密
基于多队列切换的SDN拥塞控制*
基于国产化环境的线程池模型研究与实现
核电项目物项调用管理的应用研究
线程池调度对服务器性能影响的研究*
在队列里
丰田加速驶入自动驾驶队列
基于系统调用的恶意软件检测技术研究
利用RFC技术实现SAP系统接口通信