(给自己看的笔记ing……)
进程
程序:静态的、可执行的二进制文件。存在磁盘
进程:动态的,启动-》调度-》凋亡。存在内存
定义:一个程序从启动到调度到凋亡的整个过程成为进程
进程的状态
运行:R
停止:T
等待:S
僵尸:Z(资源没有被回收,没有任何作用,还要占用内存,所以子进程结束一定要进行资源回收)孤儿进程(父亲先结束)-》会被init收养
Linux 进程管理(用户软件)
会话 使用某个会话创建的进程,属于会话管理,不是所有的进程都需依赖会话
进程组
进程
ps -aux 查看进程静态状态
top 动态监测
jobs 查看后台进程
./a.out & 放于后台执行
bg 放于后台执行
ctrl +z 挂起进程
fg 放于前台执行
kill 向进程发送信号,默认发送的信号是-9
#include <unistd.h> #include<sys/types.h>
fork()
为社么可以有两个返回值:开辟了一个子进程,子进程和父进程各有一个返回值
复制什么东西:用户空间(包含缓存区)
exit()推出进程
#include <stdlib.h>
void exit(int status); \\刷新缓存
void _exit(int status); \\不刷新缓存
第一次hello是父进程结束,但是子进程没完成继续跑,跑完为止,所以子进程成为了孤儿进程
孤儿进程:
避免出现,让父进程等待子进程结束再推出
僵尸进程:
一定避免出现,让父进程帮助回收子进程
wait #include <sys/types.h> #include<sys/wait.h>
pid_t wait (int *status); //不再进行下面的语句
参数:status退出状态
pid_t waitpid(pid_t pid,int* status,int options); //可以做其他的事情,
功能:回收子进程资源 可以设置非阻塞
返回值:成功pid,失败-1,0非阻塞
参数:pid>0 回收子进程id等于pid的进程 pid=-1 回收任意子进程 pid=0 回收同组任意子进程 pid<-1 回收组id为-pid的任意子进程 status 接收退出状态
options: WNOHANG 非阻塞 0
此时s能够接收子进程的退出状态是0 ,存的是子进程的pid
进程分类
交互进程
守护进程 (确定条件:不依赖终端,通常情况:开机执行(配置内核脚本))
日志系统
服务器
更新
制作:(不依赖终端,就不从终端输入输出)
开辟一个孤儿进程(拉高权限,能独立处理不受其他影响;创建一个子进程,父进程结束 fork exit)
创建新的会话(setsid)
更改工作目录(更改到权限更高的目录下比如 /根目录) chdir()
修改文件掩码 umask()
关闭不用的文件描述符 close()(默认一般有0、1、2三个描述符, 输入输出错误处理)
exec函数族
l:列举,第二个参数需要列举出来 NULL结尾
p:环境变量查找,可以没有路径,第一个变参数可以在环境变量搜索
v:构造指向参数的指针数组
e:用新的环境变量来代替进程的环境变量,多一个参数,可以使用指针数组传递自定义的环境变量
线程
线程轻量级,
线程之间相互容易影响,进程之间相对稳定
vfork()
子进程先执行
空间共用
pthread_create :不属于标准库,gcc时加标准库,成功返回0 不成功返回非0
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数1:线程id参数2:NULL
参数3:线程函数指针
参数4 :参数
void pthread_exit(void *retval);
功能:退出线程 返回值:无 参数:retaval,返回的状态
int0(pthread_t thread, void **retval);
功能:等待某个线程结束 返回值:0成功 参数:thread 线程id retavl:接受退出状态(阻塞等待)
练习:父进程:创建一个子进程,每秒打印一个hello
父进程:创建一个子进程,调用该ls
父进程:创建一个子进程,接受标准输入A创建一个线程每秒打印一个数字(1)
B结束所有开辟出来的线程
结合属性:需要主动回收(要做其他事情)用join
分离属性:自己回收(不做其他事情)用detach
int pthread_detach(pthread_t thread);
功能:线程分离,分离之后线程结束自动回收资源 返回值:0成功 参数:thread线程id
-
共享内存: 在多线程程序中,如果多个线程访问同一个内存位置(如全局变量
data
),那么这些线程就是在共享内存。当一个线程修改了内存中的值,其他线程可以立即看到这些修改。
线程通信
线程通信
使用全局变量进行通信
互斥
互斥锁实现互斥,在创建线程之前,所以访问共有的资源要互斥
创建一个互斥锁:
pthread_mutex_t mutex; //全局变量(所有的线程都要用)
初始化:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
返回值:0正确 参数mutex:锁 attr:属性 默认NULL
上锁:
int pthread_mutex_lock(pthread_mutex_t *mutex) //加锁,获取不到锁会挂起
返回值:0正确 参数mutex:锁
解锁:
int pthread_mutex_unlock(pthread_mutex_t *mutex) //解锁
返回值:0正确 参数mutex:锁
销毁:
int pthread_mutex_destory(pthread_mutex_t *mutex)
返回值:0正确 参数mutex:锁
尝试锁:
int pthread_mutex_trylock(pthread_mutex_t *mutex)
返回值:EBUSY 被占用 参数mutex:锁
同步
可以规定执行的顺序,但是不是说一人一次(只规定谁先谁后)
#include <semaphore.h>
创建信号量:
sem_t sem
初始化信号量:
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:sem:信号量 pshared: 0进程和线程通信 value>=0 返回值:0和-1
v操作:
int sem_post(sem_t *sem);
功能:生产 +1 返回值0和-1 参数sem:信号量
p操作:
int sem_waitt(sem_t *sem);
功能:消费 -1 返回值0和-1 参数sem:信号量
想通信要一人一次:可以设置信号量的值,比如r_sem、w_sem....
……………………
进程通信
管道通信
无名管道:
用于具有亲缘关系的进程之间即组id相同;具有固定的读端和写端,是半双工通信,无名管道是一种特殊的文件,使用IO操作。
#include <unistd.h>
int pipe(int pipefd[2]);
功能: 参数:pipfd:包含两个元素的整型数组 返回值:0成功-1失败
fd[0]用于固定的读 fd[1]用于固定的写
在写端没有关掉的时候会出现阻塞状态等待写操作,但是 写端关掉读端不会阻塞
有名管道:
用于任意管道之间即进程的组id不同
#include <sys/types.h>
作业:
1.用有名管道实现非亲缘进程的通信
2.创建两个子进程,父进程负责回收资源
子进程1,负责给子进程2发送指令
子进程2,接受指令
指令1,开辟两个线程,线程2给全局变量赋值A-Z,线程2顺序打印,打印一次就退出两个线程(考虑资源回收问题)
指令2,子进程2结束,子进程1结束,父进程打印推出信息回收资源
信号
ipc对象通信
内存共享
最快的进程通信方式,支持亲缘或者是非亲缘通信
1、 创建/打开共享内存 ftok
key_t ftok( char *pathname, int n);
功能:返回一个唯一不重复标识
返回值:失败-1 成功key
参数:pathname 路径 n:数值,一般使用字符
int shmget(ket_t key, int size ,int flag)
功能:创建/打开一个共享内存
返回值:
参数:key值 size:共享内存的大小 flag: IPC_CREAT IPC_EXCL 0666
2、映射共享内存
void *shmdt(int shmid ,void *shmaddr, int shmflag);
功能: 映射共享内存
返回值:成功返回映射的地址,失败(void)* -1
参数:shmid: 共享内存id
shmaddr:NULL系统分配
shmflg: 0默认读写 SHM_RDONLY
3、操作内存(读写操作)
4、取消共享内存映射
void * shmdt(const void *shmaddr);
功能:取消映射
返回值:成功0 失败-1
参数:被映射的地址
5、删除共享内存对象
int shmctl (int shmid , int cmd , struct shmid_ds *buf );
功能:操作共享内存
返回值:成功0 失败-1
参数:shmid:共享内存id
cmd:IPC_STST(获取对象属性)
IPC_SET(设置对象属性)
IPC_RMID(删除对象)
buf:删除 可以填NULL
ipcs -m:显示当前的共享内存
信号灯集
配合共享内存使用实现共享和互斥
消息队列
#include <sys/msg.h> #include <sys/types.h> #include<sys/ipc.h>
创建/打开消息队列 msgget
函数定义: int msgget(key_t key, int msgflg);
函数参数: key:IPC_PRIVATE 或 ftok的返回值
shmflg:权限位
IPC_CREAT:如果不存在则创建一个
IPC_EXCL:确保创建一个新的消息队列,否则失败
返回值:消息队列ID
函数定义: int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数参数:
msqid:消息队列ID
msgp:消息结构体指针
msgsz:消息结构体数据大小
msgflg: IPC_NOWAIT 消息没有发送完成函数也会立即返 回。
0:直到发送完成函数才返回
返回值:成功返回0,失败-1msgrcv
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
函数参数:
msqid:消息队列ID
msgp:消息结构体指针
msgsz:消息结构体数据大小,如果接收的数据大于msgsz 则会截取数据
msgtyp: 0:接收第一个
>0:接收指定type为msgtyp的消息
<0:接收消息队列中类型值不小于msgtyp的绝对值 且类型值又最小的消息。
msgflg: 0:若无消息函数会一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG
返回值:成功返回字节数函数定义:
.销毁消息队列 msgctl
函数定义: int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数参数: shmid:要映射的共享内存区标识符
cmd:
IPC_STAT:获取内存段状态
IPC_SET:设置内存段信息
IPC_RMID:销毁内存段
返回值:成功返回02.添加消息/读取消息 msgsnd/msgrcv
思考:什么是死锁?
怎么去防止死锁?
套接字socket(网络编程)