Linux进程学习
进程与进程管理:
清屏:system("clear"); //#include <signal.h>
进程环境与进程属性:
什么是进程:简单的说,进程就是程序的一次执行过程。
进程的状态:进程基本三态:运行态、就绪态、封锁态(等待态)——状态可在一定的条件下变化。(其中处于等待的进程分为:可中断进程可以被信号中断其等待;不可中断进程在任何情况下都不可被中断,一直等待条件的满足)。僵死进程:子进程先于父进程退出;从子进程终止到父进程调用wait()之前的时间段内,子进程被称为僵死进程zombie(因为只有父进程能回收,却没有回收其资源,所以父进程一定要wait,不然子进程就真的僵死了)/ 孤儿进程:父进程先于子进程退出,子进程被称为孤儿进程(由进程0/init进程来回收其资源)
进程的执行模式与类型:执行模式分为用户模式—中断/系统调用—>内核模式。进程类型分为用户进程—中断/系统调用—>系统进程。
进程的属性:查看进程的属性:非实时ps aux/auxf、实时top。每一列的含义(有空再看)。
会话(进程组的集合):一个会话可以没有控制终端,也可以与一个终端建立连接,建立连接的会话首进程称为控制进程;一个会话中的几个进程组,可分为一个前台进程组(当会话带有一个终端时,才有前台进程组)和多个后台进程组。其特点:无论何时在终端输入中断信号(ctrl+c)或程序退出信号(ctrl+z),就会有中断信号或退出信号发送给前台进程组的所有进程;进程组中,只要有一个进程存在,该进程组就存在。
通过进程的PID获取/设置进程组号(PGID):getpgid(pid) / int setpgid(pid, pgid)。
获取进程的会话号:pid_t getsid(sid),返回会话号;创建新的会话(而不是修改):pid_t setsid()返回进程号,该进程作为会话首进程。
终端控制函数(返回或操作对象是前台进程组号):pid_t tcgetpgrp(文件描述符)、pid_t tcsetpgrp(文件描述符,pid_t pgrpid)、pid_t tcgetsid(文件描述符)。文件描述符是终端的文件,即通过终端的文件描述符来获得/设置终端的前台进程组号(如果是设置,那么这个新的前台进程组也应该要是同一会话中的进程组),以及获得终端对应的会话ID。
获得进程用户属性:
真实用户号(RUID),即创建进程的用户ID:uid_t getuid()。
有效用户号(EUID),一些情况与UID相同:uid_t geteuid()。——>setuid?。
进程用户号(GID),即创建进程的用户所在组号GID:uid_t getgid()。
有效进程用户组号(EGID),一些情况与GID相同:uid_t getegid()。——>setgid?。
进程的管理:
创建进程:
pid_t fork();执行成功后,如果父进程抢到了执行权,则返回子进程的PID,如果子进程抢到了执行权,则返回0,否则执行失败,返回-1;这个函数是系统调用,对父进程复制,所以子进程几乎与父进程一样,代码相同,对文件采用共享方式,但是数据和文件描述符采用独占方式。
vfork()函数与父进程共享数据空间,这种方式执行效率较高,执行顺序是子先父后。
退出进程:
设置进程即将退出之前,要调用的函数:on_exit(test_exit, (void *)str);该函数有两个参数,第一个是:进程结束前,调用的test_exit函数,如void test_exit(int status, void *arg){...},test_exit函数的第一个参数必须是进程结束时exit(status)的status;第二个(应该不止示例中的参数)的参数就是:传递给test_exit函数的arg,的str。
进程的正常结束void exit(int status):进程的缓冲区数据自动写回、关闭未关闭的文件。#include <stdlib.h>
void _exit(int status):进程的缓冲区数据不会自动写回、不会自动关闭文件。#include <unistd.h>
等待进程(等待子进程中断或结束):pid_t wait(int *status);停止当前进程的执行,直到有信号到来或者其子进程结束。如果子进程已结束,执行wait时会立即返回子进程id和结束状态(保存在参数status中)。status也可以不写,还有一些测试宏(使用需要#include <stdlib.h>,具体有哪些暂时就不管了,考试考到了一看就知道)。有错误(没有子进程)则返回-1。一发现终止的子进程,就根据其pid释放子进程占用的task_struct和系统空间堆栈(就是资源),然后把该子进程的CPU使用时间加到其父进程上。
替换当前进程:#include <unistd.h>
默认情况下,新的代码(替换后的代码)仍可以使用,原来的文件描述符(因为并没有关闭),但是可以用fcntl(fd,SETFD,CLOEXE),设置为在执行完exec系列函数后,自动关闭原来打开的文件描述符。多数的exec函数,最后一个参数都是NULL,除了。而且对于所有的exec,若成功替换执行,则此函数不返回,否则返回-1。
int execl(const char *path, const char *arg, ...),参数:另一个可执行文件(执行这个文件,相当于就是这个进程执行另一个进程的内容,就达到了替换的效果),另一个进程(替换进程)的命令行参数。
int execlp(const char *file, const char *arg, ...):第一个参数:从PATH环境变量中,查找file这个文件,找到便执行。
int execv(const char *path, const char *argv[]):与execl不同,execv只有两个参数,因为所有的命令行参数,都放在argv这个二维数组中(其实就是一个字符串数组)。
int execvp(const char *file, const char *argv[]):execlp ' 1 + execv ' 2 = execvp。
execve(const char *path, const char *argv[], const char *envp[]):envp成为新的环境变量,即如果替换进程用到环境变量,则以envp为准,如char *envp[] = {"PATH=/bin", 0}。
进程的调度算法(暂时不管)。
进程间通信:
一些基本概念:
进程同步:一个功能未完成,就不返回(一件事做完,才做下一件)
进程异步:各做各的,每当有一件事做完后就通知调用者。
IPC:进程间通信。每个IPC机制都有唯一ID,通过KEY创建。同一种机制用ID区分。创建key:ftok(文件名,相同的值(如0xFF)),返回Key。
三种继承自UNIX的IPC机制:信号、PIPE、FIFO。
三种继承自System V的IPC机制:信号量、消息队列、共享内存。
有很多地方的地址都设置为NULL,表示由系统自动确定内存起始地址。
同主机,进程间数据同步交互机制:无名管道(PIPE)、有名管道(FIFO)、消息队列、内存映射、共享内存,管道和消息队列都自带同步机制,内存映射、共享内存则无同步。
同主机,进程间异步机制:信号(signal)
信号安装:
signal(信号,函数)——>函数可以不带参数,也可以带一个参数(参数为信号,信号就是一堆int值)。
sigaction(信号,信号结构体,信号结构体)。——>第二个参数安装现在的信号(如果为空指针,则保持原来的信号不变),第三个为之前的信号结构体。
信号结构体:1、.sa_handler信号处理函数。2、.sa_mask信号处理函数执行过程中,阻塞掉的其他信号。3、.sa_flags用于更改指定信号的行为。
管道的创建都不用头文件。
无名管道PIPE:每个管道只有一个内存页面做环形缓冲区,用两个管道可以实现全双工。
管道的创建:int pipe(int files[2]);参数为文件描述符,0为读,1为写;成功返回0,否则-1;写入的数据被读出就消失。然后就可以通过两个文件描述符files[0]、files[1]进行进程间的数据交互。
命名管道可保存为文件系统中,的特殊的设备文件,所以进程随时都可以通过命名管道进行I/O操作。
命名管道创建:通过命令:mkfifo fileName(还可以通过命令使用、删除FIFO);系统调用:int mkfifo(文件名, 管道文件权限),成功则返回文件描述符,否则返回-1。用法:先创建文件(用vi创建都可以,反正共同的文件一定要有),然后就可以得到文件描述符(就和无名一样了,却可读可写)
内存映射:
将文件或其他对象映射进内存(进程的空间):void *mmap(void *start,length,int prot,int flags,int fd,offset),内存起始地址(一般为NULL),长度(从偏移量offset开始算起),内存访问权限(就是PROT_WRITE、PROT_READ),映射对象的类型(匿名访问适用于亲缘进程,而非亲缘进程一般就选MAP_SHARED),文件描述符,偏移量(一般为0);成功执行则返回映射区的指针,否则返回-1。
(内存访问权限prot) (映射对象的类型flags)
让信息立即写回到文件中:int msync(内存起始地址,长度,flag),这个flag和前面的不一样:MS_ASYNC让内核尽快将信息写回文件、MS_SYNC在此函数返回之前将信息写回。
解除进程空间中的映射关系(释放内存段):int munmap(起始地址,长度),起始地址(mmap返回的指针的值);成功则返回0(解除后内存中的更改才会写回文件),否则返回-1,成功解除之后,如果再访问该映射地址,将会产生段错误。
使用方法:非亲缘进程:用open打开文件,得到文件描述符fd,再结合mmap建立内存映射,得到共有的内存地址之后就可以通信了(最后一定记到解除映射,关闭文件);亲缘进程就直接匿名访问内存,不用打开文件。
共享内存:
双方必须要用相同的起始地址的共享内存,否则交互内容不一样
共享内存使用步骤:
创建共享内存int shmget(key,size,flag);成功则返回ID号,否则返回-1。
映射共享内存,将共享内存映射到具体的进程空间void *shmat(id,addr,flag),addr通常为NULL,flag为映射地址访问权限;成功则返回共享内存起始地址,否则返回-1。
解除映射int shmdt(shmat返回的地址),如果失败则返回-1;两边要同时解除映射。
共享内存控制(用来删除共享内存就行了)int shmctl(ID,IPC_RMID,0),这一步只需要消费者来扫尾就行了
shmget函数的flag:
- IPC_CREAT:如果共享内存不存在则创建,否则打开。
- IPC_EXCL:如果共享内存不存在则创建,否则报错。
消息队列:
创建和打开消息队列int msgget(key,IPC_CREAT),第二个参数为flag和shmget的flag一样;成功则返回ID号。
添加/发送消息int msgsnd(ID,结构体缓冲区,大小,0),成功则返回0,否则返回-1。
读取/接收消息int msgrcv(ID,缓冲区,大小,类型,0),其中类型可以为0,表示可以接收任何类型的消息;成功则返回0,否则返回-1。
控制消息队列int msgctl(ID,IPC_RMID,0),一般直接用来删除消息队列就行了,所以和删除共享内存的shmctl一样,设置得比较简单。
//msgsnd函数的第二个参数void *buf :表示自定义的msgbuf结构体
struct msgbuf {
long type; //一般要求接收和发送不一样就行,如send=1,recieve=2
char msg[自定义大小];
};
实际使用(前面说明,后面例子):
首先使用ftok,创建key,mqkey = ftok(fileName, 0xFF);
然后用msgget创建消息队列,mqid = msgget(mqkey, IPC_CREAT | IPC_EXCL | 0666);
设置好缓冲区:struct msgbuf msg; msg.mtype = 随便但一致; 。。。
然后发送消息msgsnd,msgsnd(mqid, &msg, strlen(msg.mtext) + 1, 0);或者接收消息msgrcv,msgrcv(mqid, &msg, 256, 2, 0);
最后删除消息队列(至于谁来扫尾),msgctl(mqid, IPC_RMID, NULL);
同主机,进程间同步机制:信号量(semaphore)
信号量(互斥和同步):
//PV操作(原语):P为等待(-),V为信号(+)
procedure p(var s:samephore){
s.value=s.value-1;
if (s.value<0) sleep(s.queue);
} procedure v(var s:samephore){
s.value=s.value+1;
if (s.value<=0) wakeup(s.queue);
}
创建一个信号量 / 取得一个信号量的ID:int semget(key,信号量数,flag),信号量数量,一般为1,flag 访问权限 | IPC_CREAT | IPC_EXCL。
改变信号量的值:int semop(ID,struct sembuf *sops,nsops),第二个参数为系统结构数组,第三个为数组元素个数。
//函数semop的第二个参数struct sembuf *sops :解释这个结构体
struct sembuf {
unsigned short sem_num; //no:信号量编号
short sem_op; //对信号量的操作,若sem_op>0,则信号量+sem_op;若sem_op<0,则信号量-sem_op;若sem_op=0,表示判断信号量是否=0。
short sem_flg; //建议选择SEM_UNDO(进程退出时,执行 信号量解除(undo) 操作);IPC_NOWAIT(指定操作若还未完成,进程也不等待,立即返回-1)
};
直接控制信号量信息:int semctl(ID,semnum,cmd,。。。),该函数最多只有4个参数:
- semnum为信号量编号,若为设置为0,则表示整个信号量的集合(此时第四个参数无效)。
- 如果对整个信号量集合控制,则须#include <ipc.h>,此时cmd的含义与msgctl相同,有如下值:
IPC_RMID:删除整个信号量集合
IPC_SET:设置ipc_perm参数
IPC_STAT:获取ipc_perm参数
IPC_INFO:获取系统信息 - 若对单个。。。(今后再议)
网络中,主机间数据交互机制:套接字(socket)、RPC。
Linux进程学习的更多相关文章
- Linux 进程学习
1.linux进程间通讯 继承unix进程间通讯:管道 信号 AT&T :system V IPC 通讯进程只能在单个计算机 :信号量 消息队列 共享内存 ...
- Linux进程学习(孤儿进程和守护进程)
孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如 ...
- Linux进程学习 - 孤儿进程和守护进程
孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如 ...
- linux进程学习笔记
学习了linux下的进程,觉得应该整理一下,忘得差不多了,顺便回顾一下. 学而时习之,不亦说乎~~ 进程笔记 ,什么是进程? The Single UNIX Specification, Versio ...
- Linux 进程学习笔记
1.什么是程序?什么是进程?它们有什么区别? 定义: 程序:程序(Program)是一个静态的命令集合,程序一般放在磁盘中,然后通过用户的执行来触发.触发后程序会加载到内存中成为一个个体,就是进程. ...
- linux 进程学习笔记-进程ID,PID
PID,进程号 , 范围在2~(??为什么需要这么多),而一个名为idle (或swapper)的进程占据的编号0,init进程占据了编号1. 进程0和进程1 : 系统启动时会从无到有地创建进程0,它 ...
- linux进程学习-进程描述符的存储
当进程被新建时,内核会给进程分配一个8K的空间作为进程的内核堆栈.同时我们知道task_struct结构体也会被创建,但有意思的是,内核不会给task_struct单独分别空间,而是直接将其扔到8k的 ...
- linux 进程学习笔记-进程调度
在分时系统中,系统将CPU时间划分成无数个时间片(quantum)分配给不同的进程,一个时间片只执行一个进程,并且不停地切换,以让用户感觉到各个进程是在“同时运行”,这中间所需要的策略和算法便是进程调 ...
- linux 进程学习笔记-进程跟踪
进程跟踪 long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); Linux用ptrace来进行进 ...
- linux 进程学习笔记-进程信号sigal
信号(或软中断)是在软件层次上对中断的一个模拟,其运行在“用户空间”,一个进程对另外一个或几个进程通过发送信号来实现异步通信.当接收进程接收到信号后,其可以注册一下处理函数来说对这些信号进行处理(也可 ...
随机推荐
- Java内存模型深度解析:总结--转
原文地址:http://www.codeceo.com/article/java-memory-7.html 处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会 ...
- android黑科技——完美解决界面逻辑的数据框架DataBinding(最新)的使用(二)
昨天我们一起学习了dataBinding的基础用法,我想你可能还停留在它只是不用再findViewById,其实不然,今天我们就来扩展延伸,看看这个框架到底有什么魔力让谷歌官方大力推崇.这里还没看昨天 ...
- 你真的会玩SQL吗?冷落的Top和Apply
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- Linux下安装Redis
1. 下载最新版本的Redis源代码: 命令:wget http://download.redis.io/redis-stable.tar.gz 2. 解压并编译 命令:tar xzf redis-s ...
- FunDA(1)- Query Result Row:强类型Query结果行
FunDA的特点之一是以数据流方式提供逐行数据操作支持.这项功能解决了FRM如Slick数据操作以SQL批次模式为主所产生的问题.为了实现安全高效的数据行操作,我们必须把FRM产生的Query结果集转 ...
- 利用Spring AOP机制拦截方法一例
直接上代码: @Aspect // for aop @Component // for auto scan @Order(0) // execute before @Transactional pub ...
- C#、JAVA操作Hadoop(HDFS、Map/Reduce)真实过程概述。组件、源码下载。无法解决:Response status code does not indicate success: 500。
一.Hadoop环境配置概述 三台虚拟机,操作系统为:Ubuntu 16.04. Hadoop版本:2.7.2 NameNode:192.168.72.132 DataNode:192.168.72. ...
- Windows安装RabbitMQ集群的几个注意点
记录一下RabbitMQ在windows平台下安装的几个注意点- -,好记性不如烂笔头 安装过程与Linux安装一致,教程参照官网集群配置:此处只列举出几个注意点: 1. erlang的版本需要一致, ...
- jQuery的案例及必知重要的jQuery选择器
Jquery能做什么 访问和操作DOM元素 控制页面样式 对页面事件进行处理 扩展新的jQuery插件 与Ajax技术完美结合 Jquery的优势 体积小,压缩后只有100KB左右 l强大的选择器 出 ...
- powerdesigner显示列描述信息
将Comment中的字符COPY至Name中 -------------------------------------------------- Option Explicit Validati ...