进程间通信的方法主要有以下几种:
(1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
(2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该 函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
(4) 消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺
(5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
(7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
(8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
线程通信方法:
(1)共享内存
同一进程中的多个线程可以访问同一内存空间
(2)管道
主要分为一下步骤:
首先建立管道流,并将管道流的输入输出对象进行链接;
将管道流加入到生产对象(线程)中;
通过管道流引出输入输出流,并在线程中对这些流进行操作;
线程同步:同步就是协同步调,按预定的先后次序进行运行
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
线程同步的方式和机制
临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作
线程的让步:
实际运行中,有时需要使当前运行的线程让出CPU,使其他线程得以执行,这时就需要使用线程让步的操作。线程让步包括两种方式:
(1)线程只是让出当前的CPU资源,具体将CPUP让给谁不确定。
(2)线程将给指定的线程让步,指定的线程没有完成,其绝不恢复执行。
1. 使用yield方法
调用yield方法可以使当前正在运行的线程让出CPU,回到准备状态,进而使其他线程有进入运行状态的机会。但要注意的是,该操作是没有保障的,很可能线程回到准备状态后又立刻调度再次进入运行状态,也就是说yield让步不一定成功。
因此,使用yield方法真正保证做到的是正在运行的线程回到准备状态。
2. 使用join方法
当一个线程必须等待另一个线程执行完毕才恢复执行时,可以使用join方法。顾名思义,join方法可以达到将两个线程合并的效果。
1、join线程
当一个线程需要等待另一个线程执行完毕再执行的话,就调用join方法,例如,线程 A B ,A要等B执行完再执行,则在A执行时要调用B的join方法,使A进入阻塞状态,当B执行完之后再执行A;
2、线程睡眠
sleep(指定的毫秒数),在线程休息的时候,其他线程不会获取CPU的执行权限,如下代码:每隔一秒打印一次
3、线程让步:
线程让步和线程睡眠差不多,唯一的区别就是:在让步期间会放弃CPU的执行权限 Thread的 yiled静态方法
4、线程的优先级
线程优先级高的比较容易获得CPU的执行权限,优先级低的不太容易获得CPU的执行权限,但是当线程进行竞争是,不一定优先级高的一定会获得执行权限。
static int MAX_PRIORITY
线程可以具有的最高优先级。 值是10
static int MIN_PRIORITY
线程可以具有的最低优先级。 值是1
static int NORM_PRIORITY
分配给线程的默认优先级。 值是5
生产者消费者的问题:
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。