C++中的进程和线程的通信交互

一.死锁的问题

原因:多个进程或线程共享资源造成的一种僵持状态:1.竞争系统资源;2.进程的推进顺序不当;
产生的必要条件:1.互斥条件;2.请求和保持条件;3.不可剥夺条件;4.环路等待条件;
解决死锁:
预防死锁:通过有序的资源配置,足够的资源分配;
解决死锁:强行剥夺资源;撤销进程等;

二.线程间通信

1.通信方式

信号槽通信
Qt特有的通信方式,可在类之间,线程之间进行信息交互或通信
共享变量
最常用的方式,对于一些全局变量,多个线程同时操作,需要用原子变量或者用互斥锁临界区等多线程同步解决线程安全问题
自定义消息
借助于windows程序的消息通信机制,当两个线程之间至少有一个为UI线程,那么就可以直接通过SendMessage或者PostMessage来发送消息到指定线程进行响应。这种方法涉及到线程的切换,如果SendMessage/PostMessage指定的窗口是由调用线程创建,那么就是一个普通的子程序;如果指定窗口由另一个线程创建,也即UI线程,那么系统会挂起当前工作线程,切换到ui线程,并调用合适的窗口过程(PostMessage则直接进消息队列)
promise、future语法
promise对象通过promise.get_future()函数和future对象联系起来,promise对象通过set_value设置值,而future对象通过get获取值。这在两个不同线程内也可以执行。在get没有获取值值之前该线程被阻塞。这里的T是任意类

2.通信安全

(1)临界区
通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。EnterCriticalSection() 进入临界区,LeaveCriticalSection() 离开临界区,EnterCriticalSection()
(2)互斥锁
为协调共同对一个共享资源的单独访问而设计,互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,所以任何情况下此共享资源都不会同时被多个线程所访问。互斥量比临界区复杂。因为使用互斥不仅可以在多线程中实现资源的安全共享,而且可以在不同多进程之间实现对资源的安全共享。CreateMutex() 创建一个互斥量,OpenMutex() 打开一个互斥量,ReleaseMutex() 释放互斥量,WaitForMultipleObjects() 等待互斥量对象
(3)原子变量
通过原子操作给原子类型指定bool、char、int、long、指针等类型作为模板参数,原子是不可被CPU上下文交换的机器指令,这些指令组合在一起就形成了原子操作。在多核CPU下,当某个CPU核心开始运行原子操作时,会先暂停其它CPU内核对百年来所在内存的操作,以保证原子操作不会被其它CPU内核所干扰,其内部使用CAS循环,所以无需加锁即可实现线程安全。
(4)信号量
信号量对象对线程的同步方式互斥锁临界区等方法不同,信号允许多个线程同时使用共享资源 ,只限制访问共享资源的线程最大数目。信号量操作函数:CreateSemaphore() 创建一个信号量,OpenSemaphore() 打开一个信号量,ReleaseSemaphore() 释放信号量,WaitForSingleObject() 等待信号量
事件Event
事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。事件的几个函数:CreateEvent() 创建一个事件,OpenEvent() 打开一个事件,SetEvent() 回置事件,WaitForSingleObject() 等待一个事件
join函数
通过C++11新特性的join函数来进行线程的流程控制管理,对线程进行阻塞,确保线程安全

3.Qt中多线程使用

创建继承自Qthread的子类,重写父类的Run方法,实现子线程要处理的业务,再用start启动方法。优点:代码实现简单,但在一个子线程中处理多个任务,所有的处理逻辑都需要写到run()函数中,这样该函数中的处理逻辑就会变得非常混乱,不太容易维护
从QObject派生一个普通的工作类,添加成员函数来实现子线程要处理的业务逻辑,在主线程中创建QThread对象,和前面的工作类对象,通过moveToThread()将工作对象移动到创建的子线程对象中,调用start()启动子线程,最后手动调用工作类对象的对应函数即可真正在让其在子线程中执行。优点:可以创建多个类似的工作类,将各自的业务流程作为成员函数,然后将这个业务类的实例对象移动到对应的子线程中moveToThread()就可以了,这样可以让编写的程序更加灵活。
使用Qt的线程池,线程池其实由三部分组成:任务队列,工作的线程,管理者线程。Qt中的 QThreadPool 类管理了一组 QThreads, 里边还维护了一个任务队列。QThreadPool 管理和回收各个 QThread 对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局 QThreadPool 对象,可以通过调用 globalInstance() 来访问它。也可以单独创建一个 QThreadPool 对象使用

4.VS中多线程使用

MFC中使用AfxBeginThread来创建线程,该函数使用完后会自动释放掉线程句柄
WinAPI中使用CreateThread来创建线程,CreateThread 和CloseHandle是成对的,程序是不会自动释放线程句柄。在不用时需要调用CloseHandle函数释放线程句柄
C++11中的std::thread线程类,实现多线程,其构造函数会立即启动线程,并且线程的生命周期与std::thread对象绑定。因此,在使用std::thread时,不需要显式调用类似"start"的方法

三.进程间通信

1.通信方式

(1)共享文件模式
通过多个进程共同读写同一个文件来实现通信,如管理多个进程的配置文件CFile的read(),write()
(2)映射文件模式
通过两个或多个进程映射同一个文件映射对象的视图来实现的,CreateFileMapping(),OpenFileMapping(),MapViewOfFile(),UnmapViewOfFile();
(3)共享内存模式
通过多个进程来调用操作原始内存的模式实现,ReadProcessMemory()和WriteProcessMemory()
(4)管道方式
管道是半双工模式,效率差。匿名管道:是不命名的,它主要用于单机版的本地系统中父进程与它启动的子进程之间的通信。命名管道则高级一些,通过一个名字进行标识,使客户端和服务端应用程序能够通过该管道进行通信。命名管道能够在不同系统的进程间使用,这使它成为许多客户/服务器应用程序的理想之选。CreateNamedPipe(),ConnectNamedPipe(),CreateEvent(),WriteFile().
(5)消息方式
消息是利用Windows的驱动机制进行进程通信,就是使用消息激活某种操作的过程。对于进程间的通信,有用户自定义的消息和Windows消息,适合少量数据的频繁通信,根据定义的消息号用SendMessage发送
(6)信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源,Linux下定义了多种信号量,使用比较常见
(7)套接字socket
socket是最常见的进程间通信方式,尤其是跨网络情况下,常见的客户端/服务器模式就是典型的跨网络进程交互,通过三次握手四次挥手实现安全的通信

2.通信安全

(1)加join,使其变为串行
(2)使用互斥锁确保进程间安全的访问共享资源,互斥锁既可用于线程也可用于进程

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值