注意:进程是程序执行和资源管理的最小单位。
调度算法: 先进先出 / 短进程优先 / 高优先级优先 / 时间片轮转
前后台进程转换
ctrl+c 终止进程 结束进程 回到shell
ctrl+z 挂起,把前台进程转换成后台进程,回到shell ,进程没结束
jobs 查看当前在后台执行的进程的进程pid (命令 jobs -l)
fg + n 其中的n是jobs的序列号 不是pid的值,在后台暂停,程序没结束。(fg 1)
& 在可执行程序后加去地址符号,则进程默认转换成后台进程(./a.out &) 和当前终端没关系 没法用ctrl+c 和ctrl+z 来结束和挂起(需要补充)
bg N 将前台进程转换成后台进程运行。 (bg n)
新建状态:应用程序被创建时的状态,没有进入到就绪队列中。
就绪状态:进行已经具备运行条件,等待系统分配处理器运行(放入到就绪队列中)
运行状态:进程正在运行
阻塞状态:又称之为等待状态或者睡眠状态。进程在等待一个信号或者系统资源
停止:也叫死亡状态,进程完成任务后正常结束。
进程的三要素:
每个进程都有进程id,是唯一的标志
每个进程都有pcb,内核中秒数进程的主要数据 一个结构体
每个进程都会进行内存映射。
ps: 列出活跃的进程
ps -au 列出所有进程 但进程都和终端有关系
ps -aux 列出所有进程,包括有关系和终端没关系的进程。
top 动态显示进程信息,等价于任务栏管理器
top -d n秒 每隔n秒刷新一次信息。
pstree 打印进程的树状信息,关系信息。
ps -ef 标准的格式显示系统的进程信息
kill 发送信号给进程
列出所有信号 kill -l
给进程发信号 kill -信号 PID
1) SIGHUP 终端关闭会发送 进程结束
2) SIGINT ctrl + c 终止当前进程 进程结束
3) SIGQUIT ctrl + \ 停止当前进程 进程结束
9) SIGKILL 杀死进程 进程结束
12) SIGUSR2 用户自定信号
14) SIGALRM 闹钟信号
19) SIGSTOP 进程暂停
20) SIGTSTP ctrl+z 挂起进程 转换成后台进程
函数原型 pid_t getpid(void);
头文件: #include #include
返回值: 当前进程的进程id号
函数原型:pid_t getppid(void);
作用: 获取当前进程的父进程id号
练习:把当前进程的进程id和父进程的进程id打印在屏幕上
父进程改变某一个变量,子进程不改变。返回值有2个,返回给父进程的是子进程的PID,返回给子进程的是0,如果失败返回-1;
是以共享的方式访问父进程的内存,如果父进程的内存修改,子进程同时修改。vfok中是优先子进程执行,子进程结束后再执行父进程。
2.3 clone( ) 是linux内核创建进程的方式,创建进程和线程都使用的clone函数,开发中尽量避免使用,因为不利于移植。
练习: 父子进程执行不同的代码
#include
#include
#include
int main()
{
printf("danny帅\n");
pid_t pd = fork();
//子进程执行pid == 0中的代码
if(pd == 0) { while (1) { printf("我是子进程\n"); }}
//父进程执行else中的代码
else { while (1) {printf("----我是父进程--------\n"); }}
printf("pid = %d\n",pd);
printf("好帅\n");
//从fork开始的代码,在父进程和子进程中都有一份
return 0;
}
写操作拷贝技术:fork创建新进程,但不会产生父进程的副本。当子进程需要修改父进程内容的时候,才会拷贝需要修改的内存空间。父进程同样。
用vfork创建一个子进程,公用变量x 父子进程分别打印。
作用:在一个进程中执行另外一个进程,例如在a.out进程中执行b.out
#include
extern char **environ; 全局变量,已经定义好了,直接声明后使用,字符串的首地址,环境变量。
函数作用:列举的方式传参
函数参数:path 可执行程序的位置
arg 参数 需要执行的命令 可变长。
返回值: 失败返回-1 成功返回0错误信息存在errno中
作用:优先到PATH路径中查找,其他功能和execl一样。
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
作业: 自行学习四个函数,并且写测试代码。
作用:在一个进程中执行另外一个进程,例如在a.out进程中执行b.out
特点: exec 执行后他取缔了原来进程的数据段,代码段,堆栈,执行完成后,原来调用的进程内容除了进程号外,其他内容全部替换。
使用: 如果当前进程想执行另外一个进程,但自己没有其他事情可做,自己结束执行exec中的进程。
#include
extern char **environ; 全局变量,已经定义好了,直接声明后使用,字符串的首地址,环境变量。
函数作用:列举的方式传参
函数参数:path 可执行程序的位置
arg 参数 需要执行的命令 可变长。
返回值: 失败返回-1 成功返回0错误信息存在errno中
案 例:execl("/bin/ls" ,"ls","-l",NULL);
作 用:优先到PATH路径中查找,其他功能和execl一样。
参 数: file 文件名 (会在path路径中查找)
arg后的参数和execl一样
int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp[] */);
作 用: 在envp中查找执行程序和命令
int execv(const char *path, char *const argv[]);
作 用: 在数组中寻找执行命令
int execvp(const char *file, char *const argv[]);
作 用: 执行文件在file中查找但其他命令在数组中查找
int execvpe(const char *file, char *const argv[], char *const envp[]);
作 用: 在path中查找执行文件,其他命令在数组和环境变量中查找。
总结: l 列举的方式 list
v 数组的方式传参 数组也要NULL结束
p 可执行程序名再PATH路径中查找
e 环境变量传参
进程的终止:第一种 自愿终止,main函数return
第二种:被迫终止, 调用exit系列函数。
接受信号也会终止
原理:当进程结束时,内核通知父进程,在父进程处理前,这个子进程是僵尸进程,占用的各种资源被回收,进程描述符任然存在。
#include
作用:退出进程
参数: status 状态码,给到父进程
特点: 做善后处理。刷新缓冲区,释放放缓冲区,退出进程,调用了_exit
#include
作用:退出进程
参数: status 状态码,给到父进程
特点: 立马退出,直接退出、
面试题:请讲下 exit()和_exit的区别:_exit()执行后会立即返回给内核,而exit()会做一些善后处理,然后将控制权交给内核。
#include
#include
作 用: 等待子进程结束,堵塞函数。只要有进程结束则立马返回,不管是哪个进程。
参 数: status 子进程退出时候的状态码
如果不关心子进程的退出码 则直接传入NULL
返回值: 如果成功返回子进程的id 失败返回-1; errno
在等待所有进程,只要有一个进程结束 wait就会返回。
WEXITSTATUS(status)
状态信息需要通过当前宏的修改才能使用,不可以直接使用wait的状态信息。
练 习: 请创建3个子进程,保存进程id号,然后父进程等待所有子进程结束后打印出结束后的子进程id。
作用: 等待某一个进程结束,或者某几个进程结束。
参数: pid 需要等待的进程id
status 状态码 是子进程中exit的传出值
options 是0表示堵塞。 WNOHANG 是非堵塞(不等待)
pid的可能值如下:
< -1 等待进程组id为pid绝对值的组下任意一个子进程id.
-1 等待任意的子进程,等价于wait
0 等待任意的进程 这个进程组的id是等于调用的进程id.
> 0 等待进程id是pid的子进程结束。.
进程组: 当运行某一个可执行程序,创建一个进程。同时会创建一个进程组,这个进程组的id就是当前进程的id,如果这个父进程创建了子进程,
这些子进程都有自己的pid,他们都属于父进程的组id中,他们属于同一个组。
练习: 请创建三级进程 父进程 子进程 孙子进程 在子进程中等待孙子进程 在父进程中等待子进程。等子进程结束 则父进程也一起结束。
终端:是系统和用户交互的界面,从当前终端产生的进程都依附于当前终端。如果当前中断关闭,对应的前台进程会自动关闭,但是守护进程突破此现值,
第一步:创建子进程,父进程退出
if(fork() > 0 ){ exit(0);}
第二步:在子进程中创建新的会话。(会话中 各种进程组)
setsid 用来创建一个新的会话,并且当前进程成为新会话的组长。
第三步:设置文件的权限掩码。增加守护进程的灵活性
umask(0);
第四步:更改当前目录
chdir 改变当前目录。 一般情况下修改成根目录或者/temp 为守护进程的当前目录
再将父进程的三个默认打开的文件重定向 dup2();
第五步: 关闭文件描述符。
原因:新建的子进程会继承父进程的所有打开的文件描述符。(fork)
在完成会话后,为了防止资源的浪费。关闭不用的文件。
close 函数 或者fclose
getdtabsize 可以获取最大的文件描述符。 sysconf()
main函数善后 void (*function)(void)
#include
函数原型:int atexit(void (*function)(void));
函数作用:main函数接受后需要做的时期,可以调用的函数。
函数参数: (*function) 函数指针,返回值是void 参数是void的函数
#include
int on_exit(void (*function)(int , void *), void *arg);
函数作用:main函数接受后需要做的时期,可以调用的函数。
函数参数:(*function) 函数指针,返回值是void 参数是void的函数
系统日志:
使用原因:系统日志文件
打开系统日志文件
#include
void openlog(const char *ident, int option, int facility);
参数: ident 提示字符串
option:LOG_PID 把消息加入到进程id中
int facility : LOG_DAEMON 守护进程。
void syslog(int priority, const char *format, ...);
作用:写日志,
priority 优先级 LOG_INFO 普通日志
LOG_ERR 错误消息
需要写的内容
void closelog(void);
作用:关闭日志文件
作业:把当前进程的进程id 写入到系统日志文件中,然后创建2个子进程,分别写5条日志到系统日志中。主进程等待所有子进程结束。后关闭日志日志文件。
多进程通信
1.早期: 无名管道 有名管道 信号
IPC : 共享内存 信号量 信息队列
网络: socket通信
是一个文件,系统维护的一个文件,内核中。
特点: 只能用于亲缘关系的进程之间(父子 子孙..)
半双工的通信方式,同一个时间只可以由一个方向发给另外一个方向
有固定的读写端
管道可以看成是特殊的文件,对于他的读写可以用read和write函数
基于文件描述符的通信方式,当一个管道建立,有两个描述符
fd[0]用于读文件 fd[1]用来写文件
头文件 : #include
作用: 创建一个无名管道
参数: fd的数组,fd【0】,fd[1].
返回值: 如果成功返回0 失败返回-1.错误信息存入errno
注意点: 有写管道,就一定有读管道,否则会炸裂。
在写端存在的情况下:
管道有数据: read返回实际读取的数据字节数。
管道无数据: read是处于堵塞状态,直到管道有数据才解除堵塞
如果有读数据,写端如果不存在则会一直read堵塞,如果写端存在则不会出现。
为了解决不相关的进程之间的通信,也是一个文件。
头 文 件: #include #include
作 用: 创建有名管道,管道名字叫pathname
参 数: pathname, 路径 也叫管道名
mode 创建管道文件的模式 0666
返回值: 如果成功返回0 失败返回-1
写一个进程,把屏幕上输入的内容写入管道,第二个进程读出来。
理解: 进程通信的方式,他不传递数据,只传递通知。信号可以理解成中断,异步通信方式, 信号可以在用户空间和内核空间之间进行交互。
信号处理方式:
忽略信号:对信号不做任何处理,但有两个信号不可以忽略,SIGKILL SIGSTOP
捕捉信号:定义信号处理函数,当信号发生时,执行对应的函数
缺省操作:linux对每种信号都做了默认操作。
信号命令: kill -命令 pid
注意:编号为1到31的信号是传统的unix支持的信号,是不可靠信号(非实时),不存储,不放入信号队列。信号容易丢失,不排队速度快
32~63 信号,是扩展信号,叫做可靠信号,存入消息队列,不会丢失。相对来说速度不够快。
信号处理函数:
函数原型:int kill(pid_t pid, int sig); 【重】
头文件: #include #include
参 数: pid 需要发送哪个进程的id, sig 是需要发送的信号
> 0 发送sig信号给pid的进程(一个进程)
0 发送给正在调用的进程组所在进程下的所有id
-1 发送sig信号给所有进程(除了1号init进程)
<-1 给进程组为绝对值pid的组发送sig信号。
返回值:如果成功返回0 如果失败返回-1 错误信息存入errno
#include
函数原型: int raise(int sig);
作 用: 给当前进程发送信号,相当于 kill(getpid(),sig)
参数: 需要放的信号内容
返回值: 如果成功返回 0,失败返回-1,错误信息errno
作业:用有名管道写一个服务器和客户端
客户端:父进程每一秒产生一个子进程,每个子进程往有名管道写一个自己pid,以及当前的系统时间,
服务器:从无名管道中读取数据并且打印到屏幕上。
闹钟信号:
函数原型:unsigned int alarm(unsigned int seconds); 【重】
头文件: #include
作用:在参数seconds秒后发送一个闹钟给自己,信号名称:SIGALRM---14
返回值: 如果先前没有设置闹钟,成功返回0,失败返回-1
如果之前设置了闹钟,返回之前设置的闹钟剩余秒数,
注意: 一个进程只可以设置一个闹钟,不可以多个,当第二次设置闹钟的时候,不会成功,只会返回第一个闹钟剩余的时间。等价于得到闹钟的剩余秒数。
堵塞当前进程
函数原型: int pause(void);
头文件:#include
作用: 让当前进程处于堵塞状态,等待接受一个信号(终止信号或者引起调用信号处理函数的信号)
如果是非终止信号或者是不需要捕获的信号,则不会解除堵塞。
前者是等待另外的进程发送sigkill信号,而wait是父进程等待子进程的结束。
回调函数: typedef void (*sighandler_t)(int);
头文件: #include
参数: signum 信号的值,需要处理什么信号
handler 参数:
如果想忽略信号(SIG_IGN) 1
如果想默认操作(SIG_DEL)0
对信号自定义处理的回调函数地址
返回值:返回先前处理函数的指针,如果没有先前的处理函数则返回自己。如果失败返回SIG_ERR (-1)
练习:请自定义处理ctrl+z 信号。 (我是ctrl+z)
SIGUSR1
练习: 写一个代码,让子进程每隔5秒给父进程发送一个消息 ,父进程得到消息后,在屏幕上打印一句话。 (day03/09childContFather.c)
定义: 共享内存是最高效的进程间通信方式。进程之间可以直接读写内存。不需要其他的数据拷贝。一般情况下,共享内存是不安全的,
在写的过程中是可以立马读的,所以数据有可能不完整。为了解决这个问题,需要用到锁机制。
流程: 【重】
1.创建或者打开共享内存 shmget函数
2.映射共享内存 shmat 函数
3.内存的读写。 使用指针读写。
4.删除共享内存 shmdt (shmctl)
头 文 件:#include #include
作 用 : 创建或者打开共享内存。
参 数:key 是内核识别ipc的一个标志。
两种获取办法: ftok获取 第二种方式:系统自动给与 IPC_PRIVATE
size 共享内存的大小,以字节为单位,如果是0则是获取共享内存。
shmflg:权限, IPC_CREAT|0666 如果不存在则创建,如果存在则打开
返 回 值: 返回key相关的共享内存的id,如果失败返回-1,如果key相同则id也相同。
头 文 件:#include #include
作 用:根据路径名和id产生一个唯一的pic的key值。
参 数:pathname 一个路径,相同的路径和相同的id产生的key值相同
id 工程的id,自定义的,任意8位都行
返 回 值:如果成功返回 key值,如果出错返回-1
头 文 件:#include #include
作 用:将申请到的共享内存空间映射到4G的虚拟内存的某一个位置。
参 数:shmid,共享内存的id 是shmget函数的返回值
shmaddr 需要映射的地址,一般情况下是NULL,系统自动分配
shmflg 标志,一般情况下写0 表示可读可写。
返 回 值:如果成功返回 映射的首地址,如果出错返回-1
函数作用:讲共享内存从映射中删除。
函数参数:shmaddr 是shmat的返回值,也是映射的地址。
返回值: 如果成功返回0 失败返回-1
#include
#include
函数参数:shmid 是共享内存的id 是shmget的返回值
cmd 是命令,需要控制共享内存的命令
IPC_STAT 获取共享内存的信息 存入到buf中
IPC_SET 设置共享内存的信息。
IPC_RMID 删除共享内存。注意和shmdt的区别
函数作用: 可以控制共享内存
返回值: 如果成功返回0 失败返回-1
struct shmid_ds {
struct ipc_perm shm_perm; /* 操作权限,是三种ipc的共有的结构体 */
size_t shm_segsz; /* 共享内存的大小,字节数*/
time_t shm_atime; /* 最后加载的时间 */
time_t shm_dtime; /* 最后离开的时间 */
time_t shm_ctime; /* 最后修改时间 */
pid_t shm_cpid; /* 创建共享内存的进程id */
pid_t shm_lpid; /* 在该段 shmat的进程id */
shmatt_t shm_nattch; /* 使用该共享内存的进程数目*/
...
};
#include
自行查询: void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
消息队列:消息队列是ipc系列的一种对象,一种进程间通信的方式
每个消息队列都有他的id唯一标志。
用户可以在消息队列中添加消息和读取消息(收发数据)
1、得到key值 ftok
2、得到消息队列的id, msgget
3、数据的收发 msgsnd msgrcv
4、删除消息队列 msgctl
头 文 件: #include #include #include
函数作用:创建消息队列并且返回消息队列的id值。
函数参数: key值,ftok的返回值,IPC_PRIVATE
msgflg IPC_CREAT |0666
#include
#include
#include
函数作用: 往消息队列发送数据 (和write有点相似)
函数参数: msgid 是消息队列的id值
msgp 需要发送数据的缓存 (需要有自己固定的结构体)
struct msgbuf {
long mtype; /* 大于0的消息类型 */
char mtext[1]; /* 需要发送的数据,正文内容 */
};
msgsz 发送数据的大小 ,实际发送的正文内容的大小
msgflg 如果是0则表示堵塞,发送完毕后再返回,如果不堵塞IPC_NOWAIT
返回值: 如果成功返回0 失败返回-1
函数作用: 接受消息队列中数据 (和read有点相似)
函数参数: msgid 是消息队列的id值
msgp 需要接受数据的缓存
msgsz 发送数据的大小
msgtyp 消息的类型(消息的范围)
0 消息队列中的第一个消息。
>0 接受消息队列中第一个msgtyp类型的消息
<0 接受消息队列中 不大于msgtyp 类型的绝对值的最小类型的第一个消息。
msgflg 如果是0则表示堵塞,发送完毕后再返回,如果不堵塞IPC_NOWAIT
#include
#include
#include
函数参数: msqid, 消息队列的id值
cmd, 需要控制消息队列的命令
IPC_SET 设置消息队列的属性
IPC_STAT 获取消息队列的状态
IPC_RMID 删除消息队列
函数作用: 控制消息队列(关闭 获取 设置)
返 回 值: 如果成功返回0 失败返回-1
0、或者key值,ftok
1、打开或者创建信号量 semget (semaphore)
2、信号量的初始化(semctl) 不一定需要
3、p、v操作 semop()
4、删除信号量 semctl
头 文 件: #include #include #include
函数作用:创建或者打开信号量
函数参数:key 是ipic的key值,第一种ftok IPC_PRIVATE
nsems 信号量的个数 如1 ,2
semflg IPC_CREAT | 0666;
返回值: 如果成功返回信号量的id 失败返回-1
注意: p操作把当前进程的运行状态设置为堵塞状态,直到另外一个进程唤醒。申请一个空的资源(信号量减一)如果申请成功直接退出,
如果失败,进程堵塞,一直等待,直到有进程v操作为止。
v操作负责把一个堵塞的进程唤醒(释放资源)(信号量加一)
函数参数:semid 信号量的id semget函数的返回值
struct sembuf {
unsigned short sem_num; /* 信号的第几个。信号量的编号 */
short sem_op; /* 信号量的pv操作,如果是-1则是p操作,如果是v则1*/
short sem_flg; /* 标志位 默认为0 */
};
nsops : 需要操作的信号量的个数
函数作用: 给信号量做pv操作,p则信号量减一 v是信号量加1
返回值:成功返回信号量的标识符 失败返回-1
头文件: #include #include #include
函数作用: 删除 修改 初始化 信号量 做信号量的操作
函数参数: semid 信号量的id 是semget函数的返回值
cmd 操作信号的命令
IPC_RMID 删除信号量
SETVAL 设置信号量的值
GETVAL 获取信号量的值
semnum 信号量的编号。使用单个信号量的时候 默认是0
第四个参数:
union semun { //当前联合需要自行定义
int val; /* 设置信号量的时候使用 */
struct semid_ds *buf; /*IPC_STAT, IPC_SET的时候需要的buf结构体指针 */
unsigned short *array; /* 设置多个信号量的时候 数组指针 */
struct seminfo *__buf; /* IPC_INFO */
};
返回值: 如果是GETVAL 成功返回信号量的值,失败返回-1
如果是SETVAL 成功返回0 失败返回-1
线程创线程同步
进程: 独占4g的内存空间
linux内核 对每个进程都要pcb task_struct 保存
每个进程之间都参与内核的调用,彼此之间不受影响。
进程开销大(时间片轮转,开销和加载)
线程:
线程是cpu的最小调度单位。
同一个进程可以有多个线程,但都共享同一个地址空间。
也称之为轻量级的进程(linux没办法区分进程和线程)
特点: 大大提高了任务的切换效率。
使用进程的哪些资源:
可执行的指令。(代码)
静态数据(全局变量,常量,静态变量);
进程中的文件描述符
当前的工作目录
用户id 用户组id
线程的唯一标志:PCB
线程id
堆栈
优先级
线程的状态和属性
1. 创建线程
2.线程的分离
3.线程的处理
4.线程的退出
#include
函数原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
函数参数:thread 线程对象,线程的id值
attr 线程的属性 NULL
start_routine 线程处理函数,当创建线程后,自动跳转到线程处理函数中
arg 传递给线程回调函数的参数 如果没有参数NULL
返 回 值:如果成功返回0 失败返回-1
函数作用:创建线程
注意点: 在编译的过程中加 -pthread
函数原型:void pthread_exit(void *retval);
函数参数:retval 退出码,可以被主线程获取到,pthread_join
函数作用:退出线程
函数返回值: 无
#include
函数原型:int pthread_join(pthread_t thread, void **retval);
函数作用:主线程等待子线程结束,释放线程描述符
函数参数:thread 线程的id
retval 二级指针,接受线程exit的退出码。(一般情况下是一个一级指针的地址,传入地址)
返回值:成功返回0 失败返回错误errno
当线程分离后,主线程不需要等待子线程结束,不需要join也会释放子线程pcb,理解成线程的托管。分离后的线程由1号线程,也就是init线程托管。
编码步骤:(创建前分离)
作用: 对线程进行初始化,获得状态信息。通过(pthread_attr_t 获得
函数参数:attr 传出参数,传入结构体地址,会得到状态信息
返回值: 成功返回0 失败返回错误码。
函数原型:int pthread_attr_setdetachstate (pthread_attr_t *__attr,int __detachstate)
函数作用:用来设置线程分离
函数参数: attr 从init函数的第一个参数来。
__detachstate 设置或者获取分离状态
PTHREAD_CREATE_DETACHED 分离
PTHREAD_CREATE_JOINABLE
返回值:成功返回0 失败返回错误码
函数作用:获取线程的分离状态
函数参数: attr 从init函数的第一个参数来。
__detachstate 获取分离状态,是传出参数。
返回值:成功返回0 失败返回错误码
创建后分离,填入线程id后 ,此线程就变成了分离线程
头文件: #include
函数作用: 对线程进行创建后分离。
1.先对互斥锁初始化
2.加锁操作
3.数据处理
4.解锁操作
5.销毁互斥锁
函数作用: 对互斥锁进行初始化
函数参数:mutex 互斥锁对象 或者说互斥锁id
mutexattr 属性 NULL
返回值:如果成功返回0 失败返回错误码 errno
函数参数: mutex 是init的第一个参数
作用: 对互斥锁加锁。其他线程没法在加锁。
返回值:如果成功返回0 失败返回错误码 errno
作用:尝试枷锁,如果没有锁则直接返回,不等待
返回值:如果成功返回0 失败返回错误码 errno
作用: 对互斥锁解锁操作
函数参数: mutex 是init的第一个参数
返回值:如果成功返回0 失败返回错误码 errno
作 用: 对互斥锁解锁操作
函数参数: mutex 是init的第一个参数
返 回 值:如果成功返回0 失败返回错误码 errno
步骤:
1.信号量的初始化
2.pv操作
3.销毁信号量
#include
函数参数:sem 信号量的对象(传入地址,函数中会修改指针指向的空间值)
pshared 如果是0 表示线程 如果是非0表示进程。(可以处理进程和线程)
value 信号量的初值。
函数作用:初始化信号量
返 回 值:成功返回0 失败返回-1
#include
函数参数:sem 信号量对象
函数作用: 是信号量的p操作,信号量-1,占用资源
返回值: 如果成功返回0 失败-1
#include
函数参数: sem 信号量对象 sem_init的第一个参数
返回值:如果成功返回0 失败-1
函数作用: 对信号量进行v操作,是否资源,信号量+1