i.MX6ULL 嵌入式学习(一)
i.MX6ULL理论知识
- i.MX6ULL 嵌入式学习(一)
- 进程
- ps
- ipc 进程间通信
- 管道
- 信号(类似中断)
- system-V 消息队列
- system-V 信号量
- system-V 共享内存
进程
-
创建进程(复制),同程序
fork
#include<unistd.h>
a. 返回值成功 0 或 非负非零整数( 父进程返回正整数<pid 号>,子进程返回0)
失败 -1
fork 后 操作系统有两个 几乎一样的进程,fork 函数后的代码被执行两次 -
创建子进程,不同程序
exec 函数族
常用 后缀
- l: list 以列表形式 传参
- v: vector 以 向量形式传参
- p:使用环境变量 Path 来 寻找指定可执行文件
- e: 代表用户提供自定义环境变量
注意: l和v 需要任选其一,p和e 可以任意组合
且传参需要在后加
NULL
-
退出
#include<stdlib.h>
exit(status) 处理文件缓存区
_exit(status) 不处理文件缓存区
文件缓存区类似
int main() { pid_t result; result = fork(); if(result == -1) printf("fork error\r\n"); if(result == 0) { printf("son"); _exit(0); // 不处理文件缓存区 } else { printf("parent"); exit(0); // 处理 文件缓存区 } } // ------------------------------------------- 打印输出 parent 而不输出 son
d. 等待进程
#include<sys/wait.h>
#include<sys/types.h>
wait(int *status)
出现语句后可以阻塞进程,并且 可以用WIFEXITED(status)
、WEXITSTATUS(status)
,查看 等待进程时的状态
pid_t result;
int status;
result = fork();
if(result == -1)
printf("error!!\r\n");
if(result == 0)
{
printf("son\r\n");
exit(0);
}else
{
wait(&status); //堵塞 进程
if(WIFEXITED(status) == 1)
printf("exit value:%d\r\n",WEXITSTATUS(status));
return 0;
}
/*
1. WIFEXITED(status) 若此值为非0 表明进程正常结束。
若上宏为真,此时可通过WEXITSTATUS(status)获取进程退出状态(exit时参数)
2.当一个子进程终止时,父进程可以通过wait()或waitpid()系统调用来等待并获取子进程的终止状态。终止状态包含了子进程的退出状态码和一些其他信息。
3. 要使用 WEXITSTATUS 宏,需要先获取到子进程的终止状态,并将该状态作为参数传递给WEXITSTATUS,然后它将返回子进程的退出状态码。
4. WEXITSTATUS 宏本身不会引起阻塞,阻塞可能发生在使用waitpid或wait函数时,等待子进程的退出。
*/
e. 写守护进程(不受终端影响)
-
创建一个子进程,父进程直接退出;fork()
-
创建一个新的会话,摆脱终端影响;setsid()
-
改变pwd为’/'; chrdir();
-
重设文件权限掩码(umask 进行查看)
eg. 022 表示只写;真正的文件执行权限为:666&~umask; umask()
-
关闭 不需要的 文件描述符 0,1,2:标准输入 输出 出错; close();
-
不同进程伪装成守护进程 nohup
f. 僵尸进程 和 托孤进程
- 僵尸进程 : 子进程退出后,父进程没有调用wait()函数处理身后事,子进程变成僵尸进程。
- 父进程比子进程先退出,子进程变为孤儿进程,会自动把子进程挂在初始化进程上,来处理孤儿进程的身后事、
ps
ps选项
- aux(关注进程本身)
VSZ 虚拟内存 RSS 物理内存 TTY 进程关联的终端 STAT 进程的状态
START 启动时间
TIME 运行时间
COMMAND 执行的命令
axjf(进程的相互关系)
PPID 进程的父进程ID
PGID 进程所在进程组的ID
TPGID 值为-1,表示进程为守护进程
UID 用户ID
COMMAND 以ASCII码显示层次关系。
ipc 进程间通信
- 管道、信号、FIFO
- System-V ipc
- 消息队列
- 信号量
- 共享内存
- socket ipc (BSD) 支持不同设备间通信
- posix ipc(IEEE)
- 消息队列
- 信号量
- 共享内存
管道
-
无名管道
int pipe(int pipefd[2]);
返回值为0(成功),-1(失败)
- 无法open,但是可以close
- 只能通过子进程继承
文件描述符
的形式来使用 - write 和 read 都会阻塞进程
- 所有文件描述符被关闭后,无名管道被销毁
-
有名管道
int mkfifo(const char* file_name,mode_t mode)
mode 是权限
#include<sys/types.h>
#include<sys/state.h>
ps. write 具有
原子性
,整体写入,不能只写入一部分前提是内部内存是足够的
信号(类似中断)
-
kill -l 可以 查看 所有的常见类型
[learn@192 imx6ull_info]$ 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 # 1-31 信号 为常用
-
产生信号
-
硬件 : 执行非法的指令; 访问非法的内存;驱动程序
-
软件:
-
控制台:Ctrl + C 中断信号、Ctrl + | 推出信号、Ctrl + Z 停止信号
[learn@192 imx6ull_info]$ sleep 1000 ^\Quit (core dumped) # ctrl + | or abort() 退出并生成转储文件
-
kill 命令
kill -9 命令的PID号
root 权限下,且要用ps aux 提前获得PID 号
pkill
是根据命令的名字进行杀死进程的。 -
程序调用kill()函数
-
-
-
信号的处理方式
忽略、捕获、默认
处理函数(需要包含#include<signal.h>)
-
sighandler_t signal(int signum,sighandler_t handler);
handler: SIG_IGN 忽略、SIG_DFL 默认、自定义
-
kill 给自己发送信号
-
raise 给别人发送信号
过程1. signal 发送信号 2. 子进程等待信号3.父进程杀死信号4.父进程推出信号。
-
-
信号集处理函数
-
信号集
-
屏蔽信号集(自动 or 手动?)
-
未处理信号集(可以挂载屏蔽信号集)
(1-33) 非实时信号集 等到最后一个操作完成后再做出反应
(34-64) 试试信号集 排队执行 保留全部操作
-
-
处理函数
-
system-V 消息队列
-
特点
独立于进程、没有文件名和文件描述符、IPC对象具有key和ID
-
消息队列的用法
1. 定义一个唯一的key(ftok(char* path,int proj_id))path 是个合法路径、proj_id是个整数
2. 获取消息队列的ID(int msgget(key_t key, int msgflg))msgflg:IPC_CREAT如果消息队列不存在则创建;mode设置消息队列的读写访问权限
3. 发送信息到信息队列(int msgsnd(int msqid,const void *msgp,size_t msgsz, int msgflg))msgp 消息队列缓存区包括消息标识和消息内容,msgsz消息正文的字节数,msgflg:IPC_NOWAIT:非阻塞发送,0:阻塞发送
个人理解有点类似与
FPGA里的:=和<=差不多,阻塞赋值和非阻塞赋值
-
从消息队列读取消息
size_t msgrcv(int msgid, void *msgp,size_t msgsz,long msgtyp,int msgflg)
msgtyp 要接受消息的标识,msgflg:IPC_NOWAIT 非阻塞读取,MSG_NOERROR 截断消息,0表示阻塞读取
-
删除消息队列(msgctl也可以改变消息队列的属性)
system-V 信号量
信号量类似于“计数器”,作用是保护共享资源{互斥访问、同步访问},互斥访问 说明资源的
唯一性
,同步访问 说明资源的顺序性
-
函数 semget 构造信号量
-
函数 semctl(int semid,int semnum,int cmd, union semun arg) 初始化信号量,或 删除信号量
cmd :IPC_STAT 获取信号量的属性信息
IPC_SET 设置信号量的属性
IPC_RMID 删除信号量
IPC_SETVAL 设置信号量的值
union semun 共用体可以固定信息的传参
-
函数 semop(int semid,struct sembuf *sops, size_t nsops)
struct sembuf { short sem_num; // 信号量编号 short sem_op; // 信号量 P/V 操作 short sem_flg; // 信号量行为 SEMUNDO 如果未释放,可以自动释放 } // op = 1 执行 V 操作
-
父子进程的执行顺序是随机的,不过由信号量的机制就可以使得子进程在父进程之前运行。
system-V 共享内存
步骤
- 定义一个唯一的key,ftok
- 构造共享内存对象shmget
- 共享内存映射shmat
- 解除共享内存映射shmdt
- 删除共享内存
short sem_op; // 信号量 P/V 操作
short sem_flg; // 信号量行为 SEMUNDO 如果未释放,可以自动释放
}
// op = 1 执行 V 操作
- 父子进程的执行顺序是随机的,不过由信号量的机制就可以使得子进程在父进程之前运行。