进程与线程

进程与线程的区别

多进程:操作系统中同时运行的多个程序
多线程:在同一个进程中同时运行的多个任务
在这里插入图片描述

1、没有线程的系统中:进程是资源分配的基本单位,又是调度的基本单位,是系统中并发执行的单位
2、有线程的系统中:进程是资源分配的基本单位,但线程是调度的基本单位
3、引入线程的优点
(1)易于调度
(2)提高并发性
(3)开销小,创建线程比创建进程要快
(4)有利于发挥多处理器的功能

进程与线程占有的资源

1、进程中占有的资源

(1)地址空间
(2)全局变量
(3)打开的文件
(4)子进程
(5)信号量
(6)账户信息

2、线程占有的资源

(1)栈
(2)寄存器
(3)状态
(4)程序计数器

3、线程共享的内容

(1)代码段code segment
(2)数据段data section
(3)进程打开的文件描述符
(4)信号的处理器
(5)进程的当前目录和
(6)进程用户ID和进程组ID

4、线程独有的内容

(1)线程ID
(2)寄存器组的值
(3)线程的堆栈
(4)错误返回码
(5)线程的信号屏蔽码

进程间通讯与线程间通讯

线程之间的叫同步,进程之间的叫通信

1、进程间通讯IPC

进程间通信的目的和作用

(1)数据传输:将数据从一个进程发送给另一个进程,发送数据量在一个字节到几兆字节
(2)共享数据:一个进程对共享数据的修改,其他进程应该立刻看到
(3)通知事件:一个进程需要向另一个进程发送消息,通知它们发生了某种事件(例如进程终止要通知父进程)
(4)资源共享:多进程之间共享同样的资源,为了做到这一点,需要内核提供锁和同步机制
(5)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程间通信的方式
通信方法无法介于内核态与用户态的原因
管道pipe局限于父子进程间的通信
信号量无法介于内核态和用户态使用
共享内存需要信号量辅助,而信号量又无法使用
套接字在硬、软中断中无法阻塞地接收数据
消息队列在硬、软中断中无法阻塞地接收数据

1)管道

  1. 操作系统分为内核态和用户态,管道就是在内核中开辟一块缓冲区,不同的进程通过对这个缓冲取进行读写操作实现IPC。
  2. 管道有三种方式
    (1)匿名管道pipe:半双工通信,只能在父子或者兄弟进程间使用
    (2)命令流管道s_pipe:全双工,父子兄弟间使用
    (3)命名管道FIFO:半双工通信,任意进程间使用

2) 信号
信号又称软终端,通知程序发生异步事件,程序执行中随时被各种信号中断,进程可以忽略该信号,也可以中断当前程序
转而去处理信号,引起信号原因:

  1. 程序中执行错误码;
  2. 其他进程发送来的;
  3. 用户通过控制终端发送来;
  4. 子进程结束时向父进程发送SIGCLD;
  5. 定时器生产的SIGALRM;

3)共享内存

  1. 共享内存是分配一块能被其他进程访问的内存,实现是通过将内存去映射到共享它的进程的地址空间,使这些进程间的数据传送不再涉及内核,即,进程间通信不需要通过进入内核的系统调用来实现;
  2. 共享内存与其他的进程间通信最大的优点是:数据的复制只有两次,一次是从输入文件到共享内存区,一次从共享内存区到输出文件
  3. 要使用共享内存,应该有如下步骤:
    1.开辟一块共享内存 shmget()
    2.允许本进程使用共某块共享内存 shmat()
    3.写入/读出
    4.禁止本进程使用这块共享内存 shmdt()
    5.删除这块共享内存 shmctl()或者命令行下ipcrm

4)信号量
信号量是一种用于提供不同进程间或一个进程间的不同线程间线程同步手段的原语,信号量在内核中维护
信号量有三种形式:

  1. 二值信号量 : 其值只有0、1 两种选择,0表示资源被锁,1表示资源可用;
  2. 计数信号量:其值在0 和某个限定值之间,不限定资源数只在0 1 之间;
  3. 计数信号量集:多个信号量的集合组成信号量集

5)消息队列
1.从一个进程向另外一个进程发送一个带有类型的数据块,它是存储在内核中的一个消息队列(链表)
2. 使用步骤:

  1. 创建消息队列:msgget
  2. 发送数据/接收数据:msgsnd/msgrcv
  3. 释放消息队列:msgctl

6)套接字

  1. 套接字(Socket)用于协调不同计算机上的进程间通信,也就是基于网络的通信。当然,也可以在本机上使用套接字进行进程间的通信。
  2. 套接字通信分为Unix域套接字、TCP套接字、UDP套接字、链路层套接字等等。但最常用的肯定是TCP套接字。
    1.TCP Socket
    用于客户端、服务端的基于TCP协议的通信,所以在客户端和服务端均需要创建一个套接字。创建TCP套接字时会返回这个套接字的文件描述符,可通过这个文件描述符对套接字进行读和写操作。在这里插入图片描述
    2.Unix域套接字
    Unix域套接字是套接字的一种,用于本机进程间通信,一般用来实现双向通信的管道。Unix域套接字是比网络套接字轻量级且高效的多,因为它不涉及网络通信,不需要监听连接,不需要绑定地址,不需要关心协议类型,等等。
    创建Unix域套接字后返回两个文件描述符,这两个文件描述符均对套接字可读、可写,从而实现全双工的双向通信。
    同样的,为了避免使用单个文件描述符同时读、写造成的数据错乱,Unix域套接字也有两个buffer空间。
    在这里插入图片描述

2、线程间通讯 / 同步

  1. 线程间通信要简单的多。
    因为同一进程的不同线程共享同一份全局内存区域,其中包括初始化数据段、未初始化数据段,以及堆内存段,所以线程之间可以方便、快速地共享信息。只需要将数据复制到共享(全局或堆)变量中即可。不过,要避免出现多个线程试图同时修改同一份信息。
  2. 下图为多线程的进程地址空间:
    在这里插入图片描述
Linux线程同步

Linux开发:互斥锁、读写锁、条件变量、信号量、屏障、自旋锁

  1. 互斥锁
    1.互斥量本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量。
    2.互斥量的死锁:
    一个线程需要访问两个或者更多不同的共享资源,而每个资源又有不同的互斥量管理。当超过一个线程加锁同一组互斥量时,就可能发生死锁。 死锁就是指多个线程/进程因竞争资源而造成的一种僵局(相互等待),若无外力作用,这些进程都将无法向前推进。
    3.死锁的处理策略:
    1、预防死锁:破坏死锁产生的四个条件:互斥条件、不剥夺条件、请求和保持条件以及循环等待条件。
    2、避免死锁:在每次进行资源分配前,应该计算此次分配资源的安全性,如果此次资源分配不会导致系统进入不安全状态,那么将资源分配给进程,否则等待。算法:银行家算法。
    3、检测死锁:检测到死锁后通过资源剥夺、撤销进程、进程回退等方法解除死锁。
  2. 读写锁:“写独占,读共享”
    1.读写锁与互斥量类似,不过读写锁拥有更高的并行性。互斥量要么是锁住状态,要么是不加锁状态,而且一次只有一个线程可以对其加锁。读写锁有3种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。
    2.当读写锁是写加锁状态时,在这个锁被解锁之前,所有视图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是任何希望以写模式对此锁进行加锁的线程都会阻塞,直到所有的线程释放它们的读锁为止。
  3. 条件变量
    条件变量是线程可用的另一种同步机制。互斥量用于上锁,条件变量则用于等待,并且条件变量总是需要与互斥量一起使用,运行线程以无竞争的方式等待特定的条件发生。
    条件变量本身是由互斥量保护的,线程在改变条件变量之前必须首先锁住互斥量。其他线程在获得互斥量之前不会察觉到这种变化,因为互斥量必须在锁定之后才能计算条件。
  4. 信号量
    线程的信号和进程的信号量类似,使用线程的信号量可以高效地完成基于线程的资源计数。信号量实际上是一个非负的整数计数器,用来实现对公共资源的控制。在公共资源增加的时候,信号量就增加;公共资源减少的时候,信号量就减少;只有当信号量的值大于0的时候,才能访问信号量所代表的公共资源。
  5. 屏障
    1.屏障是指用户可以协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从改点继续执行。
    2.还记pthread_join函数吗?在子线程退出之前,主线程要一直等待。pthread_join函数就是一种屏障,它允许一个线程等待,直到另一个线程退出。屏障允许任意数量的线程等待,直到所有的线程完成处理工作,而线程不需要退出。所有线程达到屏障后可以接着工作。
    如果我们要让主线程在所有工作线程完成之后再做某项任务,一般把屏障计数值设为工作线程数加1,主线程也作为其中一个候选线程。
  6. 自旋锁
    1.自旋锁与互斥量类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。
    2.自旋锁可以用于以下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多的成本。
互斥与同步的区别

1.互斥
是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
2.同步
主要是流程上的概念,是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

互斥锁、条件变量和信号量的区别
  1. 互斥锁
    互斥,一个线程占用了某个资源,那么其它的线程就无法访问,直到这个线程解锁,其它线程才可以访问。
  2. 条件变量
    同步,一个线程完成了某一个动作就通过条件变量发送信号告诉别的线程,别的线程再进行某些动作。条件变量必须和互斥锁配合使用
  3. 信号量
    同步,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。而且信号量有一个更加强大的功能,信号量可以用作为资源计数器,把信号量的值初始化为某个资源当前可用的数量,使用一个之后递减,归还一个之后递增。
    1.信号量可以模拟条件变量
    因为条件变量和互斥量配合使用,相当于信号量模拟条件变量和互斥量的组合。在生产者消费者线程池中,生产者生产数据后就会发送一个信号 pthread_cond_signal通知消费者线程,消费者线程通过pthread_cond_wait等待到了信号就可以继续执行。这是用条件变量和互斥锁实现生产者消费者线程的同步,用信号量一样可以实现!
    2.信号量可以模拟互斥量
    因为互斥量只能为加锁或解锁(0 or 1),信号量值可以为非负整数,也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步
  4. 互斥锁是为上锁而优化的;条件变量是为等待而优化的; 信号量既可用于上锁,也可用于等待,因此会有更多的开销和更高的复杂性。
  5. 互斥锁,条件变量都只用于同一个进程的各线程间,而信号量(有名信号量)可用于不同进程间的同步。当信号量用于进程间同步时,要求信号量建立在共享内存区。
  6. 互斥量必须由同一线程获取以及释放,信号量和条件变量则可以由一个线程释放,另一个线程得到。
  7. 信号量的递增和减少会被系统自动记住,系统内部的计数器实现信号量,不必担心丢失,而唤醒一个条件变量时,如果没有相应的线程在等待该条件变量,此次唤醒会被丢失。
Windows线程同步:临界区、互斥量、信号量、事件

(1)临界区:对多线程的串行化访问共享资源,即在任意时刻只允许一个线程对共享资源进行访问。
(2)互斥量:互斥量跟临界区很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。
(3)信号量:允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。
(4)事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值