黑马linux系统编程

文章介绍了Linux系统中的shell命令,包括常见shell、主键盘快捷键以及目录和文件的操作。接着讲解了gcc编译过程,静态库和动态库的制作,以及gdb调试工具的使用。然后深入讨论了文件描述符、阻塞和非阻塞、fcntl和lseek函数。此外,还涉及进程和线程的概念,包括fork、wait、exec函数族,以及进程间通信的管道、信号量和信号。最后提到了守护进程的创建和线程同步中的锁机制。
摘要由CSDN通过智能技术生成

目录

 1.shell:

 1、常见shell:

2、主键盘快捷键

2、目录和文件

 head:

3、文件属性和用户用户组 

4、查找与检索

zip压缩:

5、vim编辑器

6 、gcc编译:

7、静态库的制作及使用步骤:

8、gdb调试工具

   9、Makefile项目管理

10、open函数

11、close函数

 12、错误处理函数:        与errno相关

13、read函数

14、write函数

15、文件描述符:

16、阻塞、非阻塞

17、fcntl:

18、lseek函数

19、 传入参数:

20、传出参数

21、传入传出参数

22、start/latat函数

24、目录操作函数:

25、递归遍历目录: ls-R.c

26、dup和dup2

27、fantl函数实现dup:

28、进程

29、PCB进程控制块

30、fork函数

31、gdb调试

32、exec函数族:

 33、孤儿进程:

34、僵尸进程:

35、wait函数:       

 36、waitpid函数:

 37、进程间常用通信方式:特征:

38、管道

39、 pipe函数:

40、管道的读写行为

41、pipe管道:

42、fifo管道

43、void  *mmap(void *addr, size_t  length,  int  prot,  int fd,  off_t offset);   

44、 int  munmap(void *addr, size_t  length)

45、使用注意事项:

46、mmap函数的保险调用方式

47、父子进程使用mmap进程间通信

48、无血缘关系进程间mmap通信:

49、信号

50、kill命令和kill函数

51、alarm函数

52、setitimer函数:

53、其他几个发信号函数:

54、信号集操作函数:

55、设置信号屏蔽字和解除屏蔽:

 56、查看未决信号集

57、信号捕捉:

58、信号捕捉特性:

59、守护进程:

60、守护进程创建方式:

61、线程概念:

62、线程共享:

63、线程控制原语 :

64、线程属性

65、线程同步:

66、锁的使用

67、使用mutex(互斥量、互斥锁)一般步骤

68、死锁:

69、读写锁:

 70、条件变量

71、信号量


一、cmd命令

 1.shell:

命令解释器,根据输入的命令执行相应命令。

察看当前系统下有哪些shell:

cat /etc/shells

 察看当前系统正在使用的shell

echo $SHELL

 1、常见shell:

/bin/sh (已经被 /bin/bash 所取代)
/bin/bash (就是 Linux 默认的 shell)
/bin/ksh (Kornshell 由 AT&T Bell lab. 发展出来的,兼容于 bash)
/bin/tcsh (整合 C Shell ,提供更多的功能)
/bin/csh (已经被 /bin/tcsh 所取代)
/bin/zsh (基于 ksh 发展出来的,功能更强大的 shell)

2、主键盘快捷键

| 功能      | 快捷键   | 助记             |
|-----------+-----------+------------------|
| 上          | Ctrl-p     | previous      |
| 下          | Ctrl-n     | next             |
| 左          | Ctrl-b     | backward     |
| 右          | Ctrl-f      | forward        |      
| Del        | Ctrl-d     | delete光标后面的 |
| Home    | Ctrl-a     | the first letter |
| End       | Ctrl-e     | end                |
| Backspace | Backspace | delete光标前面的 |

2、目录和文件

linux系统: “所见皆文件”

linux系统目录:

        bin:存放二进制可执行文件

        boot:存放开机启动程序

        dev:存放设备文件:字符设备、块设备

        home:存放普通用户

        etc:用户信息和系统配置文件 passwd、group

        lib:库文件:libc.so.6

        root:管理员宿主目录(家目录)

        user:用户资源管理目录

Linux系统文件类型:7/8种

        普通文件:-

        目录文件:d

        字符设备文件:c

        块设备文件:b

        软连接:l

        管道文件:p

        套接字:s

        未知文件

 ls:ls是英文单词list的简写,其功能为列出目录的内容

 -a 列出隐藏文件,文件中以“.”开头的均为隐藏文件,如:~/.bashrc

-l 列出文件的详细信息
-R 连同子目录中的内容一起列出

cd:change dir 改变当前所在路径

cd ~
cd dir1/dir2
cd ..

 which:查看指定命令所在路径

which ls

 pwd:查看当前所在路径

pwd

 mkdir:

mkdir [OPTION] DIRECTORY…
创建目录DIRECTORY,可以一次创建多个。OPTION如果是-p,表示可以连同父目录一起
创建。

rmdir:

        rmdir [OPTION]… DIRECTORY…
        删除空目录,可以一次删除多个。OPTION如果是-p,表示可以连同空的父目录一起删除。mkdir和rmdir的用法举例:
        空目录,只包含.和..的目录为空目录
$ mkdir a
$ mkdir a/b
$ ls a
b
$ rmdir a/b
$ ls a
$ rmdir a
$ mkdir a/b
mkdir: cannot create directory `a/b': No such file or directory
$ mkdir -p a/b
$ rmdir -p a/b

 touth:

touch [OPTION]… FILE…
* 将每个文件的访问及修改时间都更新为目前的时间。
* 如果文件不存在,则创建一个字节数为0的文件。

rm:

删除文件:
rm file
删除目录:
rm dir -rf

 mv

重命名:
mv file1 file2
移动文件:
mv file1 ~/

cp 

拷贝文件:  
cp file1 file2
cp file1 dir/
cp file1 ../
拷贝目录:
cp dir1 dir2 -r
cp dir1 ~/ -r

cat:

        查看文件里内容,输出到终端,如果cat时没跟文件名,则读标准输入,遇到\n后,输
出到标准输出,终端下输入Ctrl-d表示结束

 more:

more [OPTION] FILE…

         查看文本文件的内容,屏幕显示完一屏就等待用户按下任意键再滚动到下一屏,如果中

途不想继续看下去了,可以按Ctrl+C或q终止显示。

less: 

less [OPTION] FILE… 

 查看文本文件的内容,屏幕显示完一屏就等待用户按键,用户可以向上或向下查看,如  

果中途不想继续看下去了,可以按Ctrl+C或q终止显示。

 head:

head [OPTION]… FILE…
        显示指定文件的前面几行。如果没有指定文件,将从标准输入(键盘)上读取。如果没
有指定要显示的行数,则默认显示前10行。如果要显示文件的前5行:

 $ head -5 file1

tail:

tail [OPTION]… FILE…
        显示文件的最后几行。若没有指定显示的行或字符数,则默认显示末尾10行。如果要显
示文件末5行:
$ tail -5 file1

3、文件属性和用户用户组 

whoami:查看当前登录用户

软连接:

        为保证软连接可以任意搬移,创建时务必对源文件使用绝对路径

硬连接: 

        ln file file.hard

        操作系统给每一个文件赋予唯一的inode,当相同的inode文件存在时,彼此同步。

        删除时,只将硬连接计数减一。减为0时,inode被释放。

创建用户:

        sodo adduser 新用户名         ---useradd

修改文件所属用户

        sudo chown    新用户名    待修改文件

        sudo chown wangwu a.c

删除用户:

        sudo deluser 用户名

创建用户组:

        sudo addgroup 新组名

修改文件所属用户组:

        sudo chgrp 新用户组名 待修改文件

        sudo chgrp g88 a.c

删除组:

        sudo delgroup 用户组名

使用chown一次修改所有者和所属组:

        sudo chown 所有者:所属组  待操作文件

4、查找与检索

find命令:找文件

        -type 按文件类型搜索   d/p/s/c/l/f:文件

        -name 按文件名进行搜索      find ./ -name "*file*.jpg"

        -maxdepth 指定搜索深度。应作为第一个参数出现   find ./ -maxdepth 1 -name "*file*.jpg"

        -size 按文件大小搜索,单位:k、M、G     find /home/itcast -size +20M -50M

        -atime、mtime、ctime 天 amin、amin、cmin 分钟

        -exec: 将find搜索的结果即执行某一指令。 find /user/ -name '*tem*' -exec ls -ld {} \;

        -ok:以交互式的方式,将find搜索的结果集执行某一指定命令

        -xargs:将find搜索的结果集执行某一指定命令。 当结果集数量较大时,可以分片映射。

                        find /user/ -name '*tmp' | xargs ls -ld

        -print0:    find /user/ -name '*tmp*' | -print0 | xargs -0 ls -ld

grep命令:找文件内容

        grep  -r   'copy'  ./ -n                  -n:参数:显示行号

        ps aux | grep 'cupsd'              --检索进程结果集

软件安装:

        1、联网

        2、更新软件资源列表到本地:sudo apt-get update

        3、安装 sudo apt-get install 软件名

        4、卸载 sudo apt-get remove 软件名

        5、使用软件包(.deb)安装: sudo dpkg -i 安装包名。

tar压缩:

         tar -zcvf    要生成的压缩包名   压缩材料

                             tar zcvf      test.tar.gz      file1   dir2    使用 gzip 方式压缩

                             tar jcvf       test.tar.gz      file1   dir2    使用 bzip2 方式压缩

tar解压:

        将压缩命令中的c --> x         

         tar zxvf      test.tar.gz    使用 gzip 方式压缩

         tar jxvf       test.tar.gz    使用 bzip2 方式压缩

rar压缩:

        rar  a  -r   压缩包名 (带.rar后缀)压缩材料

        rar  a  -r  testrar.rar      stdio.h   test.mp3

rar解压

        unrar x 压缩包名 (带.rar后缀)

zip压缩:

        zip -r  压缩包名(带.zip后缀)压缩材料   

          zip  -r  testzip.zip      stdio.h   test.mp3

zip解压

        unzip 压缩包名 (带.rar后缀)

5、vim编辑器

跳转到指定行:

        1. 88G(命令模式)

        2. 88 (末行模式)

跳转文件首:

gg    (命令模式)

跳转文件尾:

G(命令模式)

自动格式化程序:

gg=G(命令模式) 

大括号对应:

% (命令模式)

光标移至行首:

0 (命令模式)执行结束,工作模式不变

光标移至行尾:

$ (命令模式)执行结束,工作模式不变

删除单个字符:

x (命令模式)执行结束,工作模式不变

替换单个字符:

将待替换的单词用光标选中,r (命令模式),在按欲替换的字符

删除一个单词:

dw(命令模式) 光标置于单词的首字母进行操作

删除光标至行尾:

D或d$(命令模式)

删除光标至行首:

d0(命令模式)

删除指定区域:

按V(命令模式)切换为"可视模式",使用 hjkl挪移光标来选中待删除区域。按d删除该区域数据

删除指定一行:

在光标所在行,按dd(命令模式)

删除指定N行:

在光标所待删除首行,按Ndd(命令模式)

复制一行: yy

粘贴:p:向后   P:向前

查找:

        1、找 设想内容:

                        命令模式下,按“/”输入欲搜索关键字,回车。使用n检索下一个

        2、找 看到的内容

                        命令模式下,将光标置于单词任意一个字符上,按“ * ” / " # "

单行替换:

        将光标置于待替换行上,进入末行模式,输入:s/原数据/新数据

通篇替换:

        末行模式, :%s /原数据/新数据/g           g不加,只替换每行首个

指定行的替换:

        末行模式, :起始行号,终止行号s /原数据/新数据/g           g不加,只替换每行首个

撤销、反撤销:

        u、ctrl+r(命令模式)

分屏:

        sp:横屏分。ctrl+ww切换

        vsp:竖屏分。ctrl+ww切换

跳转至man手册

        将光标置于待查看单词函数上,使用 K (命令模式) 跳转。指定卷, nK

查看宏定义:

        将光标置于待查看的宏定义单词上,使用[d 查看定义语句

在末行模式执行shell命令

        :!命令                           

6 、gcc编译:

        4步骤: 预处理、编译、汇编、连接

        -I:        指定头文件所在目录位置

        -c:        只做预处理、编译、汇编。得到二进制文件

        -g:        编译时添加调试语句。主要支持gdb调试

        -Wall:显示所有警告信息

        -l:        指定动态库名

        -L:        指定动态库路径

        -D:        向程序中“动态”注册宏定义。 #define NAME VALUE 

7、静态库的制作及使用步骤:

        1、将.c生成.o文件

                gcc -c add.c -o add.o 

        2、使用 ar 工具制作静态库

                ae rcs lib库名.a add.o sub.o div.o

        3、编译静态库到可执行文件中

                gcc test.c lib库名.a -o a.out

头文件守卫:防止头文件被重复包含

        #ifndef _HEAD_H

        #define _HEAD_H

        .......

        #endif

动态库制作及使用

        1、将.c生成.o文件   (生成与位置无关的代码 -fPIC)

                gcc -c add.c -o add.o -fPIC

        2、使用gcc -shared制作动态库

                gcc -shared lib库名.so add.o sub.o div.o

        3、编译可执行程序时,指定所使用的动态库     

                -l:指定库名(去掉lib前缀和.so后缀)-L:制定库路径

                gcc test.c -o a.out -lmymath -L ./lib

        4、运行可以执行程序 ./a.out 出错!!!  ---ldd a.out -->"not found"

          error while loading shared libraries:libxxx.so: cannot open shared object file: No such         file or directory

        原因:

                链接器:     工作于链接阶段,工作时需要-l 和-L

                动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置

        解决方式:

                (1)通过环境变量: export LD_LIBRARY_PATH=动态库路径

                        ./a.out 成功!!!   (临时生效,终端重启环境变量失效)

                (2)永久生效: 写入终端配置文件。    .bashrc    建议使用绝对路径

                                a.    vi ~/.bashrc

                                b.    写入 export LD_LIBRARY_PAHT=动态库路径   保存

                                c.     ..bashrc/ source .bashrc / 重启 终端   ---》让修改后的.bashrc生效

                                d.     ./a.out 成功!

                (3)拷贝自定义动态库 到/lib(标准C库所在目录位置)

                (4)拷贝文件法

                                a. sudo vi /etc/ld.do.conf

                                b. 写入  动态库绝对路径   保存

                                c. sudo ldconfig -v 使配置文件生效

                                d. ./a.out 成功!!! --- 使用ldd a.out 查看

8、gdb调试工具

        大前提:程序是自己写的

基础指令:

         -g:使用该参数编译可执行文件,得到调试表

        gdb a.out

        list:   l 1 列出源码。根据源码指定 行号设置断点

        b:    b 20           在20行位置设置断点

        run/r:        运行程序

        n/next:下一条指令(会越过函数)        

        s/step:        下一条指令(会进入函数)

        p/print:     p  i       查看变量的值

        continue:继续执行断点后续指令

        quit:        退出当前调试

 其他指令:

         run:使用run查找段错误出现位置

         finish:结束之前函数调用

         set args:设置main函数命令行函数

         run:字符串1 字符串2 ...: 设置main函数命令行参数

         info b:  查看断点信息表

         b 20 if i = 5 : 设置条件断点

         ptype:查看变量类型

         bt:列出当前程序正存活着的栈帧

        frame:根据栈帧编号,切换栈帧

        display:设置跟踪变量

        undisplay:取消设置跟踪变量,使用跟踪变量的编号

   9、Makefile项目管理

1个规则:

        目标:依赖条件

                (一个tab缩进)命令

                1、目标的时间应该晚于依赖条件的时间,否则,更新目标

                2、依赖条件如果不存在,找寻新的规则去产生依赖

2个函数:

        src = $(wildcard ./*.c):匹配当前工作目录下所有.c文件。将文件名组成列表,赋值给变量src

        obj = $(patsubst %. c, %. o, $(src)):将参数3中,包含参数1的部分,替换为参数2

clean:(没有依赖)

        -rm -rf $(obj) a.out        "-":作用是,删除不存在文件时不报错。顺序执行结束。

3个自动变量:

        $@:在规则的命令中,表示目标。

        $^:在规则的命令中,表示所有依赖条件

        $<:在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖取出,套用模式规则。

模式规则:

        %.o:%.c

        gcc -c $< -o %@

 静态模式规则:

        $(obj): %. o:% .c

        fcc -c $< -o %@

伪目标:

.PHONY: clean ALL

参数:

        -n: 模拟执行 make、make clean文件

        -f:指定文件执行make命令         xxxx.mk

10、open函数

        int open(char *pathname, int flags)    #include <unistd.h>

        参数:

                pathname:欲打开的文件路径名

                flags:文件打开方式:        #include <fcntl.h>

                        O_RDONLY|O_WRONLY|O_RDWR

                        O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK

         返回值:

                      成功:打开文件所对应的文件描述符(整数)

                       失败:-1,设置error

        int open(char *pathname,int flags,mode_t mode)

        参数:

                pathname:欲打开的文件路径名  

                  flags:文件打开方式:        #include <fcntl.h>

                        O_RDONLY|O_WRONLY|O_RDWR

                        O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK

                        mode:参数3使用的前提,参2指定了O_CREAT。

                                取值8进制数,用来描述文件的访问权限

                                创建文件最终权限=mode & ~mask

          返回值:         

                        成功:打开文件所对应的文件描述符(整数)

                       失败:-1,设置error

11、close函数

int close(int fd);

 12、错误处理函数:        与errno相关

               1、 printf("xxx errno: %d\n", errno);

                2、char *strerror(int errnum);

                                printf("xxx error: %s\n", strerror(errno));   

                3.void perror  (const  char *s)

                                perror("open error");                          

13、read函数

        ssize_t read(int fd, void *buf,size_t count );

        参数:

                fd:文件描述符

                buf:存数据的缓冲区

                count:缓冲区大小

        返回值:

                   0:读到文件末尾

                   成功:读到的字节数

                   失败:-1,设置errno

                        -1:bingqie errno=EAGIN 或 EWOULDBLOCK,说明不是read失败,而是read再以非阻塞方式读一个设备文件(网络文件),并且文件无数据。

14、write函数

ssize_t write(int fd, const void *buf,size_t count );

        参数:

                fd:文件描述符

                buf:待写出数据的缓冲区

                count:数据大小

        返回值:

                   成功:写入的字节数

                   失败:-1,设置errno

15、文件描述符:

        PCB进程控制块:本质   结构体

        成员:文件描述符表

                文件描述符:0/1/2/3/4......./1023        表中可用的最小的

        0 - STDIN_FILENO

        1 -STDOUT_FILENO

        2 - STDERR_FILENO

16、阻塞、非阻塞

         产生阻塞事件的场景:读设备文件。读网络文件。(读常规文件无阻塞概念)

         /dev/tty --终端文件

        open("/dev/tty", O_RDWR|O_NOBLOCK)     -------设置/dev/tty 非阻塞状态(默认为阻塞状态)

17、fcntl:

       int flags= fcntl(fd,F_GETFL);

        flags |= O_NOBLOCK

        fcntl(fd, F_SETFL,flags)

        获取文件状态:F_GETFL

        设置文件状态:F_SETFL        

18、lseek函数

         off_t lseek(int fd, off_t offset, int whence);

        参数:

                fd:文件描述符

                offset:偏移量

                whence:起始偏移位置:SEEK_SET/SEEK_CUR/SEEK_END

        返回值:

                成功:较起始位置偏离量

                失败:-1 errno

        应用场景:

                1、文件的“读”、“写”使用使用同一偏移位置

                2、使用lseek获取、拓展文件大小

                        使用truncate函数,直接拓展文件。        int ret=truncate(“dict.cp”,250)

19、 传入参数:

                1、指针作为函数参数。

                2、通常有const关键字修饰。

                3、指针指向有效参数,在函数内部做读操作

20、传出参数

                1、指针作为函数参数

                2、 在函数调用之前,指针指向的空间可以无意义,但必须有效

                3、在函数内部,做写操作

                4、函数调用结束后,充当函数返回值

21、传入传出参数

                1、指针作为函数参数

                2、在函数调用之前,指针指向的空间有实际意义

                3、函数调用结束之后,充当函数返回值

22、start/latat函数

        int stat(const char *path,struct stat *buf)

        参数:

                path:文件路径

                buf:(传出参数)存放文件属性

         返回值:

                成功:0

                失败:-1 errno

        获取文件大小:buf.st_size

        获取文件类型:buf.st_mode

        获取文件权限:buf.st_mode

        符号穿透:stat会。lstat不会

         隐式回收

24、目录操作函数:

        DIR * opendir(char *name);

        int closedir(DIR *dp);

        struct dirent *readdir(DIR * dp);

                struct dirent{

                                inode

                                char dname[256]

                }

25、递归遍历目录: ls-R.c

        1、判断命令行参数,获取用户要查询的目录名    argv[1]

                argc == 1 -->./

        2、判断用户指定的是否是目录   stat  S_ISDIR();    -->封装函数 isFile

        3、读目录:

                opendir()

                while(readdir()){

                普通文件,直接打印

                目录:

                        拼接目录访问绝对路径        sprintf(path,“%s%s”,dir,d_name)

                        递归调自己--> opendir(path)  readdir closedir

                }

                closedir()

26、dup和dup2

        int dup(int oldfd);

                oldfd:已有文件描述符

                返回:新文件描述符

27、fantl函数实现dup:

                int fcntl(int fd,int cmd,。。。)

                cmd:F_DUPFD

                参3:被占用的,返回最小可用的

                        未被占用的,返回=该值的文件描述符

28、进程

        程序:死的,只占用内存空间

        进程: 活的。运行起来的程序。占用内存、CPU等系统资源

29、PCB进程控制块

        进程id

        文件描述符

        进程工作目录位置

        进程状态:初始态、就绪态、运行态、挂起态、终止态

        *mask掩码

        信号相关信息资源

        用户id和组id

30、fork函数

        pid_t fork(void)

        创建子进程。父子进程各自返回。父进程返回子进程pid。子进程返回0

        getpid();getppid();

        循环创建n个子进程模型。每个子进程标识自己的身份

    父子进程相同:

        刚fork后。data段、text段、堆、栈、环境变量、全局目录、宿主目录位置、进程工作目录位置、信号处理方式

    父子进程不同:

        进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集

    父子进程共享:读时共享,写时复制

        1、文件描述符(打开文件的结构体)

        2、mmap建立的映射区(进程间通信共享)

31、gdb调试

        设置父进程调试路径:set follow-fork-mode parent(默认)

        设置子进程调试路径:set follow-fork-mode child

32、exec函数族:

        使进程执行某一程序。成功无返回值,失败返回-1

        int execlp(const char *file, const char *arg,...)       借助PATH环境变量寻找待执行程序

                参1:程序名

                参2:argv0

                参3:argv1

                ....:argvN

                。。。。

                哨兵:NULL

        int execl(const char *path,const char *arg,...)        自己指定待执行路径程序

        int  execvp();

ps  ajx-->pid  ppid  gid  sid

 33、孤儿进程:

        父进程先于子进程终止,子进程沦为“孤儿进程”,会被init进程领养

34、僵尸进程:

        子进程终止,父进程尚未对子进程进行回收,在此期间,子进程论为“僵尸进程”

35、wait函数:       

回收子进程退出资源,阻塞回收任意一个

        pid_t  wait(int  *status)

        参数:(传出)回收进程的pid

                失败:-1,errno

        函数作用1:        阻塞等待子进程退出

        函数作用2:        清理子进程残留在内核的pcb资源

        函数作用3:        通过传出参数,得到子进程结束状态

        获取子进程正常终止值:

      WIFEXITED(status)-->为真 --》调用WEXITSTATUS(status)--》得到子进程退出值

        获取导致子进程异常终止信号:

        WIFIGNALED(status)-->为真 --》调用WIERMSIG(status)--》得到导致子进程异常终止的信号编号

 36、waitpid函数:

      指定某一个进程运行,也可以设置非阻塞

waitpid(-1,&status,0)==wait(&status)

 pid_t  waitpid(pid_t  pid, int  *status, int optains)

        参数:

                pid:指定回收的子进程pid

                        >0:待回收的子进程pid

                        -1:任意子进程

                        0:同组的子进程

                status:(传出)回收进程的状态

                options:WNOHANG指定回收的方式为,非阻塞

        返回值:

                >0:表成功回收的子进程pid

                0:函数调用时,参3指定了WNOHANG,并且,没有子进程结束

                -1:失败。errno

        总结:

                wait、waitpid        一次调用,回收一个子进程

                想回收多个:加while

 37、进程间常用通信方式:特征:

        管道:简单

        信号:开销小

        mmap映射:非血缘关系进程间

        socket(本地套接字):稳定

38、管道

        实现原理:内核借助环形队列机制,使用内核缓冲区实现

        特质:1、伪文件

                    2、数据在管道中,只能单向流动

                    3、管道中的数据只能一次读取

        局限性:1、自己写,不能自己读

                       2、数据不可以反复读

                       3、半双工通信

                        4、学院管子进程间可用

39、 pipe函数:

        创建,并打开通道

                int  pipe(int  fd[2]);

                参数:        fd[0]:  读端

                                   fd[1]:写端

40、管道的读写行为

        读管道:

                1、管道有数据,read返回实际读到的字节数

                2、管道无数据:(1)无写端,read返回0(类似读到文件尾)

                                           (2)有写端,read阻塞等待

        写管道:

                1、无读端,异常终止(SIGPIPE导致的)

                2、有读端:        (1)管道已满,阻塞等待

                                            (2)管道未满,返回写出的字节个数

41、pipe管道:

用于有血缘关系的进程间通信

父子进程间通信

兄弟进程间通信

42、fifo管道

        无血缘关系进程间通信:

                读端:open fifo O_RDONLY

                写端:open fifo O_WRONLY

        命名管道:mkfifo

43、void  *mmap(void *addr, size_t  length,  int  prot,  int fd,  off_t offset);   

创建共享内存映射

        参数:

                addr:指定映射区的首地址。通常传NULL,表示让系统自动分配

                length:共享内存映射区的大小

                prot:共享内存映射区的读写特性。

                        PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE

                flags:标注共享内存的共享属性。MAP_SHARED、MAP_PRIVATE

                fd:用于创建共享内存映射区的那个文件的文件描述符

                offset:偏移位置。需要是4k的整数倍

        返回值:

                成功:映射区的首地址

                失败:MAP_FAILD,errno

44、 int  munmap(void *addr, size_t  length)

释放映射区

addr:mmap的返回值

 length:大小

45、使用注意事项:

        (1)用于创建映射区的大小为0,实际指定非0大小创建映射区,出“总线错误”

        (2)用于创建映射区的文件大小为0,实际指定0大小创建映射区,出“无效参数”

        (3)用于创建映射区的文件读写属性为,只读,映射区属性为  读、写。出“无效参数”

        (4)创建映射区,需要read权限。当访问权限指定为MAP_SHARED,mmap的读写权限,应该《=文件的open权限。只写不行。

        (5)文件描述符fd,在mmap创建映射区完成时即可关闭。后续访问文件,用地址访问

        (6)offset必须是4096的整数倍(MMU映射的最小单位4k)

        (7)对申请的映射区内存 ,不能越界访问

        (8)munmap用于释放的地址,必须是mmap申请返回的地址

        (9)映射区访问权限为“私有”MAP_PRIVATE,对内存所做的所有修改,只在内存有效,不会反映到物理磁盘上

        (10)映射区访问权限为“私有”MAP_PRIVATE,只需要open文件时,有读权限,用于创建映射区即可

46、mmap函数的保险调用方式

        (1)open(“文件名”,O_RDWR)

  (2)mmap(NULL,有效文件大小,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)

47、父子进程使用mmap进程间通信

        父进程  先  创建映射区    :   open(O_RDWR) mmap();

        指定MAP_SHARED权限

        fork()创建子进程

        一个进程读,另一个进程写

48、无血缘关系进程间mmap通信:

        两个进程打开同一个文件,创建映射区

        指定flags为MAP_SHARED

        一个进程写入,另外一个进程读出

        【注意】:无血缘关系间通信。mmap:数据可以重复读取

                                                           fifo:数据只能一次读取

49、信号

        共性:

        简单、不能携带大量信息,满足条件才发送

        信号的特质:信号是软件层面上的中断。一旦信号产生,无论程序执行到什么位置,必须立即停止运行,处理信号,处理结束,在执行后续指令

        所有信号的产生及处理全部都是由【内核】完成的。

        信号相关概念:

                1、按键产生

                2、系统调用产生

                3、软件条件产生

                4、硬件异常产生

                5、命令产生

        概念:

                未决:产生与递达之间的状态

                递达:产生并且送达到进程。直接被内核处理掉

                信号处理方式:执行默认处理动作、忽略、捕捉(自定义)

                阻塞信号集(子女好屏蔽字):本质:位图。用来记录信号的屏蔽状态。一旦被屏蔽的信号,在解除屏蔽前,一直处于未决态

                未决信号集:本质:位图。用来记录信号的处理状态。该信号集中的信号,表示,已经产生,但尚未被处理。

        信号四要素

                信号使用之前,应先确定其4要素,而后使用!!!

                信号编号、信号名称、信号对应事件、信号默认处理动作

50、kill命令和kill函数

         int kill (pid_t,int signum)

                pid:>0:发送信号给指定进程

                        =0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程

                        <-1:取绝对值,发送信号给改绝对值所对应的进程组的所有组员

                       =-1:发送信号给,有权限发送的所有进程

51、alarm函数

        定时发送SIGALRM给当前进程

        unsigned int alarm(unsigned int seconds)

                seconds:定时秒数

                返回值:上次定时剩余时间

                                无错误现象

        time命令:查看程序执行时间。实际时间=用户时间+内核时间+等待时间--》优化瓶颈IO

52、setitimer函数:

  int  setitimer(int which,const struct itimerval *new_value, struct itimerval *old_value)

参数:

        new _value:定时秒数

         old_value:传出参数:上次定时剩余时间

  返回值:

        成功:0

        失败:-1,errno

53、其他几个发信号函数:

        int raise(int sig)  ; 

54、信号集操作函数:

        sigset_t set:自定义信号集

        sigemptyset(  sigset_t *set):清空信号集

        sigaddset(sigset_t *set,int signum);讲一个信号添加到集合中

        sigdelset(sigset_t *set,int signum):从集合中移除

        sigismember(const sigset_t *set,int signum):判断一个信号是否在集合中

55、设置信号屏蔽字和解除屏蔽:

        int sifprocmask(int how, const sigset_t *set,sigset_t *oldset)

         how:        SIG_BILOCK        阻塞

                        SIG_UNBLOCK        取消阻塞

                        SIG_SETBLOCK        用自定义的set替换mask

        set:        自定义set

        oldset:旧有的mask

 56、查看未决信号集

        int sigpending(sigset_t *set)

        set:传出的未决信号集

57、信号捕捉:

        signal();

        sigaction();

58、信号捕捉特性:

        (1)捕捉函数执行期间,信号屏蔽字由mask--》sa_mask,捕捉函数执行结束,恢复回mask

        (2)捕捉函数执行期间,本信号自动被屏蔽(sa_flags=0)

        (3)捕捉函数执行期间,被屏蔽信号多次发送,解除屏蔽后只处理一次

借助信号完成子进程回收

59、守护进程:

                daemon进程:通常运行与操作系统后台,脱离终端控制。一般不予用户直接交互。周期性的等待某个事情发生或周期性执行某一动作。不受用户登录注销影响。通常以d结尾的命名方式

60、守护进程创建方式:

        (1)fork子进程,让父进程终止

        (2)子进程调用setsid(),创建新会话

        (3)通常根据需要,改变工作目录位置chdir()

        (4)通常根据需要,重设mmask文件权限掩码

        (5)通常根据需要,关闭/重定向 文件描述符

        (6)守护进程,业务逻辑。while()

61、线程概念:

        进程:有独立的进程地址空间,有独立的pcb   分配资源的最小单位

        线程:有独立的pcb,没有独立的进程地址空间

        ps -Lf 进程id  ---》线程号。LWP--》cpu执行的最小单位

62、线程共享:

        独享 栈空间(内核栈、用户栈)

        共享: ./text./date

63、线程控制原语 :

        pthread_t  pthread_self(void):  获取线程id。线程id是地址进程内部空间,用来标识线程身份的id

        返回值:本线程id

   

        int pthread_create(pthread_t  *tid, pthread_attr_t   *attr,void *(*start_rountn)(void *),void * arg)

        参1:传输参数,表新创建的子线程id

        参2:线程属性,传NULL表使用默认属性

        参3:子线程回调函数。创建成功,pthread_create函数返回时,该函数会被自动回调

        参4:参3的参数。没有的话,传NULL

返回值:成功0

              失败:errno

        循环嵌套N个子进程

                for(int i0;i<5;i++)

                        pthread_create(&tid,NULL,tfn,(void *)i);将int类型i,强制转换成void *,传参

void pthread_exit(void *retval):退出当前线程

        retval:退出值。无退出值时,NULL

        exit():退出当前进程

        return:返回到调用者那里去

        pthread_exit:退出当前线程

int pthread_join(pthread_t   thread, void  **retval):回收线程

        thread:待回收的线程id

        retval:传出参数。回收的那个线程的退出值        

                返回值:成功0

                      失败:errno

int pthread_datach(pthread_t thread):设置线程分离

        thread:待分离的线程id   

        返回值:成功0

                      失败:errno

int pthread_cancel(pthread_t thread):杀死一个线程。需要到达取消点(保存点)

 thread:待杀死的线程id   

        返回值:成功0

                      失败:errno

        如果子线程没有到达取消点,那么 pthread_cancel无效。

        我们可以在程序中手动添加取消点,使用pthread_testcancel()

        成功被pthread_cancel()杀死的线程,返回-1,使用pthread_join回收

线程控制原语                                                进程控制原语

pthread_create()                                             fork()

pthread_self()                                                 getpid()

pthread_exit()                                              exit()\return()

pthread_join()                                           wait()/waitpid()

pthread_cancel()                                               kill()

pthread_datach()

64、线程属性

        设置分离属性:

        pthread_attr_t   attr:        创建一个线程属性结构体变量

         pthread_attr_init(&attr):初始化线程变量

pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED)设置线程属性为分离态

      pthread_create(&tid,&attr,tfn,NULL)借助修改后的设置线程属性创建为分离态的新线程

        pthread_attr_init(&attr)销毁线程属性

65、线程同步:

        协同步调,对公共区域数据按序访问。防止数据混乱,产生与时间相关的错误

66、锁的使用

        建议锁!对公共数据进行保护。所有线程应该在访问公共数据前先拿锁在访问。但,锁本身不具备强制性

67、使用mutex(互斥量、互斥锁)一般步骤

(1)pthread_mutex_t  lock:创建锁

(2)pthread_mutex_init:初始化

(3)pthread_mutex_lock:加锁

(4)访问公共数据(stdout)

(5)pthread_mutex_unlock():解锁

(6)pthread_mutex_destory():销毁锁

初始化互斥量:

              1、   pthread_mutex_init(&mutex,NULL);动态初始化

              2、  pthread_mutex_t  mutex=PTHEREAD_MUTEX_INITALIZER;静态

        注意事项:

                尽量保证锁的粒度,越小越好。(访问共享数据前,加锁。访问结束【立即】解锁)

                互斥锁:本质是结构体,我们可以看做是整数。初值为1(pthread_mutex_init()函数调用成功)

                加锁:--操作,阻塞线程

                结束:++操作,唤醒阻塞在锁上的线程

                try锁:尝试加锁,成功--,失败,返回。同时设置错误号EBUSY

restrict:关键字:

         用来限定指针变量。被该关键字限定的指针变量所指向的内存操作,必须由本指针完成

68、死锁:

        是使用锁不恰当导致的现象

                1、对一把锁反复lock

                2、两个线程,各自持有一把锁,请求另一把

69、读写锁:

        锁只有一把。以读方式给数据加锁--读锁。以写方式给数据加锁--写锁

        读共享,写独占

        写锁优先级高                

        相较于互斥量而言,当读线程多的时候,提高访问效率

        pthread_rwlock_t  rwlock;

        pthread_rwlock_init(&relock,NULL);

        pthread_rwlock_rdlock(&rwlock)

        pthread_rwlock_rdlock(&rwlock)

        pthread_rwlock_unlock(&rwlock)

        pthread_rwlock_destory(&rwlock)

 70、条件变量

        本身不是锁!但是通常结合互斥锁来使用Mutex

        pthread_cond_t cond;

        初始化条件变量:

              1、   pthread_cond_init(&cond,NULL);动态初始化

              2、  pthread_cond_t  cond=PTHEREAD_COND_INITALIZER;静态初始化

        pthread_cond_signal():唤醒阻塞在条件上的(至少)一个线程

        pthread_cond_broadcast():唤醒阻塞在条件变量上的所有线程

        【要求,能够借助条件变量,完成生产者消费者模型】

71、信号量

应用于线程、进程间同步

        相当于初始化值为N的互斥量。N值,表示可以同时访问共享数据区的线程数

        函数:

                sem_t  sem:定义类型

        int   sem_init(sem_t  *sem,int pshared,unsigned int value);

        参数:

                sem:参数量

                pshared:        0:用于线程间同步

                                        1:用于进程间同步

                value:N值。(指定同时访问的线程数)

                sem_init(&sem,0);

                sem_destroy();

                sem_wait();        一次调用,做一个--操作。当信号值为0时,再次--就会阻塞

                sem_post();         一次调用,做一个++操作。当信号值为N时,再次++就会阻塞

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值