C语言--day29

线程间同步机制

线程间同步:
  • 定义:让多个线程任务执行某部分任务的时候具有先后顺序
  • 同步方式:信号量
  • 可以将信号量看成一个资源数,当该资源数>0的时候,可以申请到信号量,当资源时为0时,申请信号量阻塞等待。申请完信号量时,该信号量对应的资源数自动-1。释放对应的信号量时,该信号量对应的资源数自动+1
创建信号量:sem_t
初始化信号量:

int sem_init(sem_t *sem, int pshared, unsigned int value)

  • 功能:初始化信号量
  • 参数:
  • sem:初始化的信号量对象地址
  • pshared:进程间共享还是线程间
  • 0: 线程间
  • 非0:进程间
  • value:初始化的资源数
  • 返回值:
  • 成功:0
  • 失败:-1
申请信号量(P操作)

int sem_wait(sem_t *sem)
int sem_trywait(sem_t *sem)

释放信号量(V操作)

int sem_post(sem_t *sem)

销毁信号量

int sem_destroy(sem_t *sem)

死锁

  • 定义:死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,且互相请求对方未释放资源,从而导致陷入永久等待状态的情况
现象:
  • 现象1:忘记释放锁
  • 现象2:重复加锁
  • 现象3:多线程多锁,抢占锁资源不当
  • 如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁
产生死锁的四个必要条件(四条全中 = 死锁,破掉任意一条 = 解除):
  1. 互斥条件:一个资源同一时刻只能被一个任务占用(一个执行流获取锁后,其它执行流不能再获取该锁)
  2. 请求与保持条件:已经拿着一部分资源不释放,同时又去申请新的资源(执行流本身使用着一把锁并不释放,还在请求别的锁)
  3. 不剥夺条件:资源只能由持有者主动释放,系统/其他任务不能强行抢过来(A执行流拿着锁,其它执行流不能释放)
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)
死锁解决方法:
  1. 锁一定要成对出现
  2. 使线程的加解锁顺序一致
  3. 破坏环路等待条件(使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的资源)
进程间通信机制(IPC)
  • 定义:进程间空间独立,不能直接通信,数据共享需要使用IPC机制

进程间通信的方法:
同一主机间进程通信:

  1. 有名管道
  2. 无名管道
  3. 信号
  4. 共享内存
  5. 消息队列
  6. 信号量集

不同主机间进程间通信:

  1. 网络套接字
无名管道:
  • 无名管道:只能用在具有亲缘关系的进程间通信
  • 有名管道:可以用在任意进程间通信

int pipe(int pipefd2)

  • 功能:创建一个无名管道并获得两个文件描述符
  • 参数:
  • pipefd:保存读写端对应的文件描述符
  • pipefd0 --->读端
  • pipefd1 --->写端
  • 返回值:
  • 成功:0
  • 失败:-1
  • 读管道:read()
  • 写管道:write()
  • 关闭管道:close()
注意:
  1. 管道在使用时要确定它的方向,是一个单向的数据通道
  2. 管道中的数据,一旦被读走,直接剪切走数据
  3. 管道中的数据遵循先进先出的特点(FIFO)
  4. 管道默认大小65536字节,64k
  5. 管道的读端和写端不能交换
管道的特点:
  1. 读阻塞:当读写端都存在时,从管道中读数据,管道为空时,发生读阻塞
  2. 写阻塞:当管道读写段都存在时,向管道中写数据,管道满时,发生写阻塞
  3. 管道破裂:当读端关闭,向管道中写入数据时,发生管道破裂(异常)
  4. 读返回0:当写端关闭,读管道时,管道中有数据则读出数据,没有数据,则读不发生阻塞,直接返回0
有名管道
  • 定义:有名管道:同一主机,任意进程间通信。通过创建一个管道文件实现(p)

    int mkfifo(const char *pathname, mode_t mode);
    功能:创建一个管道文件
    参数:
    pathname:管道文件名称
    mode:管道文件的读写执行权限
    返回值:
    成功:0
    失败:-1
    打开管道文件:open
    读写管道文件:read/write
    关闭管道文件:close

信号
  • 信号:进程间的通知机制(异步通信)
  • 信号:软中断。CPU正在执行的任务可以被一个信号打断,中断后执行新的任务,新的任务结束继续执行之前的任务
信号的操作:
  • 发送信号 : kill、kill()
  • 注册信号:signal()
  • 信号的处理方式
  • 忽略:不处理
  • 缺省:按照操作系统默认方式处理
  • 捕获:按照自定义方式处理
kill -l 查看
复制代码
1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

	2) SIGINT:ctrl + c 
		让一个进程被打断
	3) SIGQUIT:ctrl + \
		让一个进程结束
	9) SIGKILL:
		强制让一个进程结束
	11)SIGSEGV:
		让一个进程结束(段错误)
	13)SIGPIPE:
		让一个进程结束(管道破裂)
	14)SIGALRM:
		让一个进程结束(定时时间到达)
	*17)SIGCHLD:
		子进程结束时发送给父进程(隐含的发送)
	18)SIGCONT:
		让停止态的进程继续执行
	19)SIGSTOP:
		让运行态的进程进入停止态(暂停)强制停止
	20)SIGTSTP:
		ctrl + z   让进程进入暂停态,后台进程
		来自终端的停止信号

	10 SIGUSR1
	12 SIGUSR2
	
	9	SIGKILL
	19	SIGSTOP
	不能被忽略和捕捉

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:注册一个信号
参数:
	signum : 需要注册的信号的编号
	handler:信号的处理方式
		SIG_IGN : 以忽略方式处理
		SIG_DFL :以缺省(默认)方式处理
        handler :以捕获方式处理(自定义):自定的信号任务处理函数
返回值:
	成功:返回handler
	失败:SIG_ERR

注意:
	1. 信号只需要注册一次
	2. 信号能早注册就早注册
注意:
复制代码
1. 信号函数尽可能的快、短、小,尽可能避免长延时、阻塞、休眠等耗时操作
2. 使用sigaction替代signal,可以屏蔽同源信号,防止产生信号触发嵌套

pause();
功能:让一个进程挂起(休眠)
可以使用一个信号将pause唤醒,该信号必须被捕获。
unsigned int alarm(unsigned int seconds);
功能:设置一个闹钟,闹钟时间到时可以发送一个SIGALRM信号
参数:
	seconds:设置的闹钟的秒数
相关推荐
逢君学术论文AI写作1 小时前
Java第24课:会话技术CookieSession
java·开发语言
小小编程路1 小时前
字符串转数字时,可能会遇到哪些问题?
java·开发语言·算法
许彰午1 小时前
责任链模式实战——同一个框架里的两种链
java·开发语言·责任链模式
寻道码路1 小时前
LangChain4j Java AI 应用开发实战(十四):手写 RAG 全流程 - 深入理解每个环节
java·开发语言·人工智能·ai
吴阿福|一人公司2 小时前
Python 类变量修改的压力测试:高并发场景
开发语言·python
十月的皮皮2 小时前
C语言学习笔记20260612-菱形图案打印(两种写法)
c语言·笔记·学习
天天进步20152 小时前
Tunnelto 源码解析 #13:自托管部署:Docker、环境变量、端口规划与单实例限制
开发语言
AI科技星2 小时前
第三卷:质数王朝志(全卷定稿)
c语言·开发语言·汇编·electron·概率论
kyle~2 小时前
DDS分布式实时系统---自省机制
开发语言·分布式·机器人·c#·接口·ros2