初识Linux编程
最近操作系统作业有不少linux编程的内容,啥子wait
,signal
,exit
,exec
,等等函数简直打脑壳,从来就没接触过,实在是看不懂,经过我一番研究还是有所收获
僵尸进程、孤儿进程
一说到僵尸进程,我之前听到军儿哥说过,但是还是没搞清楚,从名字上看始终就感觉想啥子病毒程序那种。
这篇博客很好。。僵尸进程与孤儿进程
总而言之喃就是,孤儿进程
就是他的父进程已经死了,子进程就成了孤儿,然后被一个init进程收养,并且这个init进程会自动处理所有的孤儿进程。而僵尸进程
就是子进程死了,但是他的父进程有没有来给他收尸,所以常年就飘泊在外面就像僵尸一样,但是这个僵尸很乖,不会像行尸走肉中的僵尸那么吃得,也不会像九叔对付的僵尸那么强,这儿的僵尸只是啥子都不敢但是占用了pid,他占用其实没啥子,关键就是这个pid是有限的,一占用多了就要出问题。
根据上面那片博客中的例子,再查看所有僵尸进程的时候可以通过top
,也可以通过ps
命令,但是ps
命令不是自动的动态更新的,所以就写个小脚本动态查看
#!/bin/bash
while true
do
clear
echo 's pid ppid commond'
echo '-------------'
ps -A -o s,pid,ppid,cmd| grep -e '^[Zz]'
sleep 1
done
这里里面-A
是查看所有的结果,-o
是自定义格式,s
是进程的状态,进程的状态有R
运行态,S
睡眠,Z
僵尸进程等。。ppid
父进程的pid
, 然后把结果再用grep
的正则表达式来筛选输出
而测试代码就是上面博客中的代码这就不粘了~
还有就是通过top的交互式命令的方式
查看生成僵尸进程
僵尸进程的预防办法就是上面那片博客中所说的通过wait
函数, 或者waitpid
函数,子进程在终结的时候都回向父进程发送SIGCHLD
信号,父进程也可通过signal
函数去处理
wait函数详细分析
然后我发现一个小东西就是进程在sleep
的时候是会别捕捉到的信号唤醒的,不管是SIGINT
这个终止进程信号,还是只是普通的闹钟信号SIGALRM
,都会影响到正在执行的那个sleep
,比如我的这一段代码
打印TTTT
之前应该是要睡100秒的(linux中好像是以秒为单位,不是以毫秒为单位),但是正因为我前面一句有个一秒钟的闹钟,所以100秒的睡眠会被唤醒
这篇博客还可以sleep与信号唤醒
然后很快就打印了很多TTTT了
Linux系统信号
上面wait
和signal
都可以接受和发送很多信号,但是这信号到都有些什么用,什么时候用?说实话我还没有自己仔细研究,先记下来,等比赛完考了研再来慢慢研究
linux内核信号是如何处理的
linux信号的默认处理
linux多线程
这篇对linux线程的讲解很详细在linux中使用多线程
我刚开始的时候,以为是pthread_join
函数才是开启线程的意思, 后头经过实验发现其实pthread_create
的时候已经就创建线程并开启线程了。
这里有个小东西就是传参的问题
#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
void test(int *input){
int i;
for(i = 0; i < 5; i ++){
printf("-------%d\n", *input);
sleep(1);
}
}
int main(){
pthread_t thread;
int input = 1;
pthread_create(&thread, NULL, (void *)test, &input);
sleep(3);
input = 2;
while(1);
return 0;
}
我在最后加了一个死循环因为如果没有这个死循环,又没有pthread_join
的情况,这个进程就不回去等自己的线程执行完就死了,所以必须要加一个东西
这段代码的结果是
为什么只出现了3个1,然后后面全是2喃?因为穿的参数是指针,而后面又改了这个指针中的内容。
exec函数族
exec函数族解析
exec函数族就是在一个进程中,去调用另一个进程,不管可以调用自己写的exe,还可以调用shell
lockf函数
这里再额外提一下lockf函数,就是控制不同进程输出的时候,不要串在一起了。。我这里只讨论lockf中第一个参数为1(也就是打印到控制台的情况)
这里有几点要注意的
- lockf函数并不会控制线程间的互斥输出,只控制进程间的互斥输出,下面是代码和结 果,毕竟这些线程都是处于同一个进程的,而
lockf
只是进程互斥 - 在实验lockf的时候可能会被
printf
或者putchar
的缓冲区机制影响是实验结果
在多进程的情况下,很容易会出现打印的时候内容串在一起的情况,我这里为了让结果更明显,我就在循环中加了sleep
函数
这段代码的结果为:
而如果加了锁的情况就不同了,这位了不让父进程先退出,子进程变成孤儿乱打印就加了个wait
这哈结果就称透了
这里虽然试验成功是因为我这里的printf
都是使用了\n
换行转义符,这个换行转义符会把printf
缓冲区中的所有内容都打印出来,但是如果没有\n
, 就有问题了,我这里为了实验,就不要lockf
函数,因为没有了lockf
函数,按理来说打印的信息是会串在一起的,但是结果变成了这样虽然没有换行,但是也应该串在一起三,而且程序不是每隔一秒打印一次,而是等整个循环执行完了才打印
Linux进程通信
进程通信的内容还是相当多的,我只是大概了解了一下管道, 命名管道, 还有啥子0, 1, 2,分别是标准输入,标准输出,错误输出,记不清楚了。。
Linux下的进程通信
Linux内核likely()和unlikely()函数
管道
管道图解
从内核源码分析管道
Linux内核分析
浅谈dup和dup2函数
Linux文件描述符
这几篇文章一起看效果最好~
开始我看到pipe(int pid[2])
函数的时候,我就很不解,传两个整数过切,为啥会跟文件扯上关系,而且还必须传一个只有两个元素的数组过切,而且每次调用pipe()
函数过后,每次fd[0] 和 fd[1]
的值都是3 和 4,这些整数其实就是文件描述符
,是系统自动分配当前进程中能够使用的最小值的文件描述符的下标。而这些文件描述符就相当于一个数组的下标,这个数组里面的内容就是指针,就如上面文章中的图所讲解的一样
这里面的文件描述符有点意思,每个进程都有自己的文件描述符可以通过在/etc/proc/${进程号}/pd
中看到瞬间就对啥子0, 1, 2这三个标准输入,输出,错误输出,有了感性的认识,其实还可以直接vim编辑一哈,还好耍
自动截图Shell
做操作系统试验的时候,老师喊我们写实验报告(一想到实验报告就感觉恶心,又要截图,又要粘代码,还要写心得体会,最弹得是还要写一段感谢信),因为当时有些人安ubuntu始终有问题,就有人请别人帮忙做的,而且我们老师就是为了防止我们用别人的截图,所以要求我们截图的时候每个人必须用自己的姓名、学号做用户名,然后我就想到整个shell,只用输入一个人的姓名、学号、用户名,所有老师要求的截图都放到一个指定的文件夹中,这样就很爽了
最后虽然成功,但是就我一个人用了,因为我都是最后才交,因为了解这些东西和整这个shell实在是费时间,确实没法我才抵拢了才交,所以也没装成逼,只给宇哥一个人看了一哈。还是把代码记录一哈,以后自己看。
#!/bin/bash
id=$1
name=$2
username=$3
shiyan='实验'
function tt(){
printf "\033[1;32m${username}@${id}\033[0m:\033[1;34m~/Desktop/
${tempshiyan}/${name}\033[0m$ ";
}
function out(){
tempshiyan=${shiyan}${count}
tt
echo ${commond}
}
imagepath="../share/testtest"
count=1;
path="backup/1实验一"
clear
#----------------------------------------
commond="gcc copyfread1024 -o copyfread1024.exe"
out
commond="time ./copyfread1024 copy.txt to.txt"
out
time ./${path}/copyfread1024.exe ${path}/copy.txt ${path}/to.txt
commond="gcc copyfread -o copyfread.exe"
out
commond="time ./copyfread copy.txt to.txt"
out
time ./${path}/copyfread.exe ${path}/copy.txt ${path}/to.txt
commond="gcc copyread1024.c -o copyread1024.exe"
out
commond="time ./copyfreadcopy.exe copy.txt to.txt"
out
time ./${path}/copyread1024.exe ${path}/copy.txt ${path}/to.txt
commond="gcc copyread.c -o copyread.exe"
out
commond="time ./copyread.exe copy.txt to.txt"
out
time ./${path}/copyread.exe ${path}/copy.txt ${path}/to.txt
sleep 1
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
commond="cat /proc/stat"
out
cat /proc/stat
sleep 1
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
./showcurse
reset
reset
count=2;
path="backup2/linux-source-4.11.0"
#----------------------------------------
cd ${path}
commond="sudo make mrproper"
out
make mrproper
commond="sudo make clean"
out
sudo make clean
commond="sudo make"
out
make
commond="sudo make modules_install"
out
make modules_install
commond="sudo make install"
out
make install
cd ../../
sleep 2
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
clear
path="backup2"
commond="./testcall"
out
./${path}/testcall
./${path}/testcall
./${path}/testcall
commond="./testcopy"
out
./${path}/testcopy
commond="cat aim.txt"
cat ${path}/aim.txt
sleep 1
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
clear
count=3;
path="backup3/fork_t"
#----------------------------------------
commond="gcc fork.c -o fork"
out
commond="./fork"
./${path}/fork
commond="gcc fork.c -o fork"
out
commond="./fork"
out
./${path}/fork
sleep 1
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
clear
path="backup3/process_t"
commond="gcc process.c -o process"
out
commond="./process.c"
out
./${path}/process
sleep 5
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
clear
path="backup3/multi_process"
commond="gcc single_process.c -o single_process"
out
commond="./single_process"
./${path}/simgle_process
commond="gcc multi_process.c -o multi_process"
out
commond="./multi_process"
out
./${path}/multi_process
commond="gcc multi_pthread.c -o multi_pthread"
out
commond="./multi_pthread"
out
./${path}/multi_pthread
imagename=$(date +%N)
scrot -u ${imagepath}/test${count}/${imagename}.png
clear
clear
count=4;
path="backup4"
#----------------------------------------
commond="gcc server.c -o server"
out
commond="gcc client.c -o clien"
out
commond="./server &"
out
commond="./client "
out
./showserver ${name} ${id}
clear
commond="gcc test.c -o test -pthread"
out
commond="./test"
out
./showtest
说实话这个shell还是有一些困难,这是我们要截图的一个例子:
- 第一就是用户名的问题,上面说了老师要求我们用自己的姓名、学号做用户名,所以我第一个思路就是在shell里面创建用户也就是用
useradd
,还在网上找了半天,才有个办法把验证密码解决的,但是!!!su
的时候就不得行了,反正我也没搞清楚咋回事,就是不能在shell中切换用户,当时脑壳都整痛了,然后上床休息了一哈,海耶突然灵机一动!,反正都是打印,我就直接手动把想打印的用户名、主机名都打印出来就完了三。你可能会说,用户名主机名都是那种颜色特别的字体,咋整喃,然后我就且找,shell还真的可以改字体!!,爽,就是这一段print"\033[1;32m${username}@${id}\033[0m:\033[1;34m~/Desktop/${tempshiyan}/${name}\033[0m$ ";
啥子\033这些都是颜色~
,然后路径名那些都自己打印 - 第二就是有一个截图是在运行一个程序的时候,我截图都是通过一个命令,在shell中可以直接调,但是在运行另外一个程序的时候我咋个截图喃?而且还要把时间搞好,这时候上面学到的进程通信的技术就派上用场了,
exec函数族
,wait
,signal
,fork
一个都不能少,说实话现在想起有点成就感 ? - 还有就是编译内核的时候咋个办喃?这个一编译起码都是一个小时,咋个截,不可能在shell头写
sleep(60 * 60)
三,这时候就要用到我之前写的这篇文章编译Linux内核的经验,方法就是自己Makefile
文件改了,哎呀,反正老师又不得细看,随便写点编译信息就脱手 - 最后就是因为每个地方都要打印命令,重复代码很多,这时候有用到了军儿哥传授的高内聚低耦合,解耦和 ?,开个玩笑~
确实当时截图的时候,那种效果还是多炫的