一,解决方法
方式一:互斥锁
方式二:信号量----让线程间有顺序协调地工作,它可以用来协调多个线程或进程,使得它们不会因为同时访问共享资源而导致数据不一致或系统崩溃。
二、信号量的操作
信号量主要有两个基本操作:
1.等待(P 操作):表示使用这个资源。
线程或进程尝试获取信号量的资源。
如果信号量的计数器大于 0,则减 1 并继续执行。
如果信号量的计数器等于 0,线程或进程将进入等待状态,直到信号量大于 0。
2.释放(V 操作):表示产生这个资源。
线程或进程释放信号量的资源。
信号量的计数器加 1。
如果有等待的线程或进程,则唤醒它们中的一个
三.信号量分类
1.有名信号量(Named Semaphore):
允许不同进程间通过名称共享信号量
用于进程间同步,可以跨进程访问。
2.无名信号量(Unnamed Semaphore):
只能在同一个进程或线程组内使用。
不需要名称,在创建时直接初始化
四、信号量的相关函数
sem_t : 数据类型,用来定义信号量
sem_t sem;(信号量定义)
定义了一个数据类型为sem_t 的变量,名为sem;
sem_init:(初始化操作)
用于初始化一个无名信号量。
原型:
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem:指向信号量对象的指针。
pshared:为 0 表示信号量用于进程内线程之间的同步;非 0 表示用于进程间同步。
value:信号量的初始值。
sem_wait:(P操作)
使调用线程阻塞,直到信号量值大于 0。
原型:
int sem_wait(sem_t *sem);
参数:
sem:指向信号量对象的指针。
sem_post:(V操作)
增加信号量的值(释放信号量)。
原型:
int sem_post(sem_t *sem);
参数:
sem:指向信号量对象的指针。
sem_destroy:(销毁操作)
用于销毁一个无名信号量。
原型:
int sem_destroy(sem_t *sem);
参数:
sem:指向信号量对象的指针。
进程间的通信方式共有七种,分为三大类(所有类型的通信都借助于内核完成)
古老的通信方式:管道和通信
ipc对象通信:消息队列,内存共享,信息量集
socket通信:网络通信
其中只有socket通信可以进行不同主机之间通信
五.管道(Pipe)
管道是一种在Unix和类Unix操作系统中用于进程间通信(IPC)的机制,它允许数据从一个进程(或线程)流向另一个进程(或线程)。管道可以分为两种主要类型:无名管道和有名管道(FIFO)。
无名管道
无名管道是用于具有亲缘关系的进程(如父进程和子进程)之间的通信。当一个进程通过fork()函数创建一个子进程后,可以使用pipe()函数创建一个无名管道,然后通过读写端的文件描述符进行数据交换。无名管道在文件系统中没有对应的文件名,因此它们是匿名的,只在创建它们的进程之间可见。
有名管道(FIFO)
有名管道,或称为FIFO(First In First Out),是一种持久的管道,它们在文件系统中表现为特殊文件,因此可以被任何有权访问的进程使用,而不局限于具有亲缘关系的进程。有名管道可以跨越进程的创建和销毁,即使创建它们的进程终止后,这些管道仍然存在,直到被系统或管理员明确删除。
管道的工作原理
管道内部是一个先进先出的缓冲区,数据只能单向流动。通常一个进程负责写入数据(写端),另一个进程负责读取数据(读端)。数据的发送者通过向管道的写端写入数据,接收者通过从管道的读端读取数据。当数据写入管道的缓冲区满时,写端将被阻塞直到有空间可用;同样,当数据读取完毕,读端将阻塞直到有新的数据写入。
pipe()函数使用方法
使用pipe()函数创建管道的一般步骤如下:
1.包含必要的头文件<unistd.h>。
2.声明一个整数数组来存放文件描述符。
3.调用pipe()函数,并检查返回值以确认管道是否成功创建。
4.使用返回的文件描述符进行读写操作。
注意事项
1.在使用无名管道时,需要确保正确管理文件描述符,避免资源泄漏。
2.由于管道的容量有限,需要处理可能出现的溢出情况。
3.在多进程环境中,应考虑同步机制以避免数据竞争。