=========================================day01====================================================
1、什么是操作系统
操作系统是管理硬件的系统,让系统正常运行起来
2、计算机的基本组成
CPU 内存 存储(硬盘 U盘 移动硬盘) 外设:键盘、鼠标、显示器
3、指令运行的过程
从内存中获取指令
通过控制器译码
通过cpu逻辑运算
把运算结果返回到内存
取址 译码 运算
4、cpu的组成
控制器 运算器 寄存器组
运算器:进行数据的运算,包括整数和浮点数
控制器:运行控制逻辑,收发控制信号
MAR:内存地址寄存器
MBR:内存缓冲寄存器
IO AR:IO地址缓冲寄存器
IO BR:IO缓冲寄存器
PC:程序计数器
PSW:程序状态寄存器
寄存器组:转悠寄存器组和通用寄存器组
程序只能访问通用寄存器阻
寄存器分三类:
控制寄存器:
数据寄存器:
状态寄存器:读硬件的状态,判断当前硬件运行状态
=========================================day02====================================================
5、系统总线
地址总线:说明是寻址空间,32位系统2^32=4G;64位系统2^64=2^32*2^32=2^32*4G
数据总线:传输数据的时候同时发送,并发发送数据的位数,20位,或者24位
控制总线:收发控制信号,比如中断、时钟、复位IO读写、存储读写、系统总线请求
6、指令格式
1)地址指令
op A1 A2 A3 A4 A1+A2结果存放到A3,A4存放下一条指令
2)3地址指令
op A1 A2 A3 A1+A2结果存放到A3,PC存放下一条指令
3)2地址指令
op A1 A2 A1+A2结果存放到A1,PC存放下一条指令
4)1地址指令
op A1 A1+ACC存放到ACC,PC存放下一条指令
5)0地址指令
op 使用到堆栈指针SP PC存放下一条指令
7、指令寻址方式
1)立即数寻址
add r0,r1,#6 以#开始的数是立即数
2)直接寻址
直接寻址是一维指针的概念
3)隐含寻址
借助ACC累加器
4)间接寻址
是二维指针的概念,指令中存储的地址的地址,需要2次取值才能把值取出来(指针里存放地址地址又存放地址)
5)寄存器寻址
地址存放在寄存器中,寄存器中存放的是一个地址
6)寄存器间接寻址
寄存器中存放的是地址的地址
7)基址寻址
需要有一个基址寄存器,每条指令的地址需要加上基址寄存器中的值,才是有效的指令地址
8)变址寻址
需要有一个变址寻址器
9)相对寻址
相对PC寻址,PC+相对地址=有效的指令地址
10)堆栈寻址
借助SP指针寻址
8、下载课件和电子书
在浏览器中输入地址:
http://192.168.1.130/LinuxNetwork.tar.gz
http://192.168.1.130/sysnetbooks.tar.gz
9、冯.诺依曼架构
1)二进制思想
2)程序顺序存储
计算机中一切程序 = 二进制 + 上下文
10、磁盘
分柱面,磁道,磁头
磁盘使如何寻址的?
磁盘在旋转,磁头也是在根据扇区寻址
扇区:512字节
分组:1K 2K 4K
分区:多个分组组成一个分区
11、计算机的发展过程
1)单通道批处理
只有一个通道,读数据的时候,CPU就处理空闲状态
2)多通道批处理
有多个通道,并发的概念,一个通道在读数据的时候,另一个通道可以使用计算机的CPU计算数据,提高计算机整体的效率
3)分时系统
把计算机的计算数据的时间分成很小的时间片,多个任务循环使用时间片,因为时间片很小(thi slice),所以对外感觉每个用户都是独占计算机的CPU
分时在系统存在4个问题:
1)如何保证多个任务安全同时运行
2)如何保证多个任务访问共享文档
3)如何实现操作系统的并发和竟态
4)操作系统内核如何为上层(应用层)提供系统统一的接口
12、现在操作系统
1)当分时系统实现了存在的4个问题之后,就度过了到现在操作系统,现在操作系统包括6部分:
任务管理:多进程或者多线程
内存管理:物理地址和逻辑地址的转化(映射),逻辑地址连续的内存空间,物理地址不一定连续
网络管理:硬件的驱动,外联设备
文件管理:ext4 fat32 ntfs yaffs2(andriod)
系统(自动)管理:shutdown init reboot halt
2)现在操作系统的类型
现在操作系统基本都是多用户多任务的操作系统
通用操作系统:
Windows
Uniux
Linux
mac OS
嵌入式操作系统:
andriod
IOS
移植裁剪过的开源的linux系统
arm stm32使用的 ucosII 购买正点原子或者野火的板子
wince
windows mobile
VxWorks
13、系统调用
操作系统的应用层向内核层收发数据的一个接口或方法,应用层把封装好的数据通过系统调用接口发送到内核层,内核层对数据进行逻辑运算,把运算的结果通过系统调用返回到应用层
可以认为应用层是客户端,内核层是服务器,所以系统调用可以认为是客户端-服务器架构
14、系统调用和glibc库的区别
glibc库是封装的系统调用,但是他并不是封装了全部的系统调用,只是封装了大部分系统调用
为什么glibc库封装系统调用:封装以后函数更容易使用更容易移植,更方便理解
比如:fopen() fclose() fread() fwrite() fseek()是glib库函数
open() close() read() write() seek()是系统调用
举例:
exit()是glibc库函数
_exit()是系统调用
int exit(int status)
{
_exit(status);
printf("\n");
return 0;
}
15、标准文件IO
1)按照字符读写
getchar() putchar()
2)按照行读写
fgets() fputs()
3)按照块读写
fread() fwrite()
4)写文件相对简单,直接写就可以
5)读文件的时候相对复杂一点,需要循环读写
while(fread(buf,sizeof(buf),1fp) > 0)
{
......
}
//以下这种写法不适
for(i=0;i<100;i++)
{
fread();
或者fgets();
或者fscanf();
}
16、标准文件IO拷贝
diff命令判断两个文件是否相同:diff src.txt dst.txt
17、打印错误信息的函数
#include<errno.h>
errno
strerror()
#include <string.h>
char *strerror(int errnum);
perror()//自动打印错误信息
#include <stdio.h>
void perror(const char *s);
18、能打开的最大文件描述符的个数
系统启动后,自动打开3个文件描述符:stdin stdout stderr
通过程序可以再打开1021个
最大文件描述符个数是1021+3=1024
ulimit -n //默认打开的文件描述符的个数
cat /proc/sys/fs/file-max //系统能支持的最多文件描述符的个数
=================================================day03=====================================================================
1、ini文件转html文件
ini 文件 (没有结束标识,下一部分的开始标志上一部分的结束)
1. ;stu//注释
[stu]//开始
zhangsan = 123456//等号两边有空格
lisi = 123456
2. ;teac//注释
[teac]//开始
wangwu = 123456
html(xml) 文件
1. <!_stu_>//注释
<stu>//开始
zhangsan=123456//等号文件两边没有空格
lisi=123456
</stu>//结束
2. <!_teac_>
<teac>
wangwu=123456
</teac>
2、中断
中断是操作系统中一个重要的概念,中断是根据进程的优先级实现的,是高优先级进程终止低优先级进程的运行,高优先级进程运行完,低优先级进程继续运行,中断是基于进程优先级,抢占式的进程调度
中断有一个中断向量表,进程中断后,在中断向量表中有记录,被中断的进程一直循环
3、阻塞,非阻赛,异步
阻赛:getchar() scanf() fgets() 没有输入,程序停止不继续运行
非阻赛:中断是非阻赛的,现象上和阻赛一样,都是程序没有继续运行,但是阻赛是停止的,非阻赛是一直在循环判断的(人走路停下来原地踏步)
异步:硬盘控制器,cpu告诉硬盘完成一个拷贝,硬盘控制器收到指令后,开始拷贝,在拷贝的时间中,硬盘控制器和cpu各自忙各自的互不影响,这就是异步。异步相当于是硬盘控制器具有了cpu的一定功能
4、系统文件类型
ls -l
-:普通的规则文件,文本文件
d:目录
c:字符设备 cd /dev/ ls
b:块设备
p: pipe 管道 特殊的文件
s:socket 特殊的文件
l:链接文件
5、链接文件
1)硬链接文件:
ln oldfile newfile (ln 1.log 2.log)
硬链接和源文件inode编号一样,是同一个文件的不同存在形式,只有把源文件和硬链接全部删除,才认为是删除了硬链接
硬链接如果删除源文件后,再生成源文件,原来的硬链接已经不存在了,需要重新建立硬链接
2)软链接文件
ln -s oldfile newfile
软链接和源文件的inode编号不一样,不是同一个文件,删除源文件,软连接文件还存在,再生成新源文件后,软连接依然存在,可以认为软连接是快捷方式
3)如何查看inode编号
ls -li
6、系统文件IO和标准文件IO区别
标准文件IO读写的是普通的文本文件和二进制文件
如:fopen() fclose() fread() fwrite() fseek()
系统文件IO不仅可以读写设备文件,还可以读写文本文件
open() clse() read() write() lseek()
比如:管道文件,socket文件只能使用read,write系统文件读写,不能使用标准文件IO读写
加锁文件,必须使用系统文件IO
7、系统文件IO
1)open()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname:文件路径,可以是相对路径也可以是绝对路径
flags:
O_RDONLY:可读
O_WRONLY:可写
O_RDWR:可读写
O_TRUNC:重新生成
O_CREAT:文件不存在创建
O_APPEND:追加
mode:
部分8进制
111 111 111 777
110 100 100 644
0644 0是粘着位表示系统用户
返回值:
正确返回新的文件描述符,错误返回-1
0 1 2 3 4 5 6
0 1 2 3 5 4
生成文件描述符规定:最小的,未用的
标准文件IO和系统文件IO文件描述符的区别
标准文件IO文件描述符:FILE *fp;
系统文件IO文件描述符:int fd;
系统启动后,自动生成3个文件描述符
0 stdin STDI_FILENO
1 stdout STDOUT_FILENO
2 stderr STDERR_FILENO
2)close()
#include <unistd.h>
int close(int fd);
fd:open 函数的返回值
返回值:正确返回0错误返回-1;
3)read()
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:open 函数的返回值
buf:读取的数据存放的内存空间地址
count:buf内存的长度
ssize_t:返回值
>0:正确返回成功读取的字节数;
如果读取的字节数小于请求的字节数,并不是错误,是因为读到了文件尾,确实比请求的字节数小(5<8):因为是读到文件结尾或者是从管道
或者是从终端读的数据
<0:错误返回-1
=0:读到文件尾
4)write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:open函数的返回值
buf:写数据内存的起始地址
count:待写数据的内存长度
返回值:正确返回写成功的字节数错误返回-1
5)lseek()
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd:open函数的返回值
offset:文件指针偏移量
whence:设置文件指针的起始地址
SEEK_SET SEEK_CUR SEEK_END
off_t:返回值 正确返回文件指针的偏移量,错误返回(off_t) -1
8、access函数
#include <unistd.h>
int access(const char *pathname, int mode);
pathname:文件相对路径或者绝对路径
mode:
F_OK:判断文件是否存在
R_OK:判断文件是否可读
W_OK:判断文件是否可写
X_OK:判断文件是否可执行
返回值:
成功返回0,失败返回-1
9、获取文件属性 stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
path:文件路径
fd:文件描述符
buf:地址传递,函数调用完后可以传出文件的属性
返回值:成功返回0,错误返回-1
1)
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
2)
S_ISREG(m) 判断是否是规则文件
S_ISDIR(m) 是否是目录
S_ISCHR(m) 是否是字符设备
S_ISBLK(m) 是否是块设备
S_ISFIFO(m) 是否是有名管道
S_ISLNK(m) 是否是符号连接
S_ISSOCK(m) 是否是socket,网络编程介绍
3)
S_IFMT 0170000 bit mask for the file type bit fields
switch(buf.st_mode & S_IFMT)
{
case S_IFREG:
braek;
....
}
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
S_ISUID 0004000 set-user-ID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
10、读目录流(一个文件或目录)
opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
name:目录的路径
DIR *pdir:打开目录后的指针
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
返回值:成功返回0,出错返回-1
11、文件属性其他相关函数
1)getpwuid
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);
char *pw_name;
2)getgrgid
#include <sys/types.h>
#include <grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
char *gr_name;
3)localtime
#include <time.h>
struct tm *gmtime(const time_t *timep);
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
4)readlink
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
path:文件路径
buf:对应的文件链接源文件的名字
bufsiz:数组的长度
返回值:正确返回读取的字节数,出错返回-1
12进程
进程是系统获取资源的最小单位
进程有5个状态:
创建 就绪 运行 阻赛 退出
就绪->运行
运行->就绪
运行->阻赛
阻赛->就绪
(阻赛不可以到运行)
13、查看进程
ps -aux
ps -ef
ps -efl
进程控制块
进程id
进程队列 双向循环链表
信号(信号集)
文件
内存
虚拟内存
cpu内存 对称SMP CPU
errno错误码
14、如何生成进程
fork()
#include <unistd.h>
pid_t fork(void);
pid_t;
>0:父进程
=0:子进程
<0:错误分支
fork函数是执行一次,有两个有效返回值。大于0的pid返回给父进程=0的pid返回给子进程,>0的pid正好是(真正的)子进程的id号
getpid:获取自己的pid
getppid:获取父进程的pid
为什么把子进程的pid 返回给父进程?
因为子进程是父进程创建的需要父进程来管理子进程,父进程就需要子进程的pid 来管理,并且没有获取子进程的pid函数
子进程我为什么返回0?
因为子进程如果需要自己pid的时候,可以通过getpid获取,还可以通过getppid获取
fork函数执行成功后,就有了父子进程,这时候父子进程是并发(同时)运行的
fork在英文中的原意是叉子的意思,在这里理解为分叉
15、fork函数的拷贝方法
可以认为fork之后,子进程完全拷贝了父进程,子进程拷贝了父进程堆栈,信号量集,文件描述符等
注意:文件锁不可以拷贝,信号量集拷贝后会清空
16、vfork(子进程先运行)
vfork不是完整的拷贝,是从父进程资源中先考贝一个可以运行的最小资源的集合,在运行的时候,需要什么资源再从父进程资源中拷贝过来,这种方法称为写时拷贝技术
17.fork vfork对比程序
18、僵尸进程
fork成功之后,父子进程在同时运行,子进程先退出,父进程没有及时给子进程善后,因为子进程即便自己退出释放了资源,毕竟是父进程生成的,也就是说父进程中肯定会有子进程相关的资源,这种现象称为子进程僵尸状态
19、孤儿进程
fork成功之后,父子进程同时运行,父进程先退出了,子进程占时没有了父进程,这是子进程称为孤儿进程,但是孤儿进程是暂时的,最后会由init进程领养
20怎样避免僵尸进程
wait()函数 waitpid()函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
作用:是父进程中调用wait,等待子进程的退出,如果子进程不退出,父进程中wait一直处于阻赛状态,wait函数的作用主要是给子进程善后
pid_t waitpid(pid_t pid, int *status, int options);
waitpid函数和wait函数作用一样都是父进程给子进程善后
status:是传地址的,所以可以把子进程的退出状态传递到wait函数的外面
pid:指定需要善后的进程号
<-1:绝对值相等的pid
-1:任意一个等价于wait
0:同组的任意一个进程
>0:指定的pid
status:善后进程的退出状态
options:0等价于wait,WNOHANG是非阻赛的
返回值:
options是0的话,返回的是善后的pid
options是WNOHANG的话,返回的是0,说明没有僵尸子进程
21、进程的pid的取值范围
进程号0表示的是系统内核
进程号1表示的是系统的init进程
其他进程依次加1
分配的原则也是最小的未用的
unsigned short
0~32767
查看进程号命令:
pstree
=======================================================day04=================================================
1.僵尸进程
父进程调用wait函数释放子进程在父进程中的资源,即便没有调用wait,父进程退出后,父进程释放的资源中就包括了子进程在父进程中的资源
2.孤儿进程
父进程退出后,子进程暂时处理孤儿进程状态,但是最后由init(inituser)进程领养
3.system系统调用 system.c
system函数调用后返回原来的程序继续运行
4.exec函数 execlp.c
exec函数调用完后,不再返回原来的程序继续运行,直接退出,也就是说exec函数后面的程序运行不到
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);
exec系统函数中的l是list的意思,列表,v是vector,向量,vector中的参数相当于封装了list中的参数列表
path:式命令的路径,比如/bin/ls /sbin/ls
file:式命令的名字,比如ls ps
函数使用方法列子
execl("/sbin/ls","ls","-l","./",NULL);//参数列表必须以NULL结尾
execlp("ls","ls","-l","./",NULL);//这里不用写/sbin
为什么可以直接写文件名,路径呢?,p指的是系统环境PATH指定的路径
命令行输入:echo $PATH
char *const envp_list[]={""PATH=$PATH,"TERM=$TERM"}
execle("/sbin/ls","ls","-l","./",NULL,envp_list);
char *const argv_list[]={"ls","-l","./",NULL};
execv("/sbin/ls",argv_list);
execvp("ls",argv_list);//p指的是PATH环境变量
execvpe("ls",argv_list,envp_list);
5.fork_exec
exec系列的函数运行完退出,只是子进程退出了,父进程并没有受到影响,还可以继续运行
6.信号量
kill -l 查看系统定义的信号量
SIGINT ctrl+c 默认退出,也可以关联到我们写的函数
SIGQUIT ctrl+\ 异常退出
SIGHKILL 关闭进程
SIGUP 当前进程和终端断开连接时产生的信号
SIGSTOP 进程暂停 ctrl+z 进程暂停后(暂停不是退出)关闭终端,暂停的进程也随着退出
SIGCHLD 子进程退出后,发送给父进程的信号
SIGABRT 信号产生时,段错误
7、kill与killall
kill -9 pid
kill -KILL pid SIGHILL
killall -9 进程名
kill -KILL 进程名
8、signal
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum:信号量
handler:取值有3个
自定义函数
SIG_DFL//自定义 这个符号表示恢复系统对信号的默认处理。
SIG_IGN//忽略 signal(SIGHUP, SIG_IGN);表示忽略SIGHUP信号
补充: handler取值自为定义函数时:signal(SIGINT,func);
一个返回值为正数的函数地址,此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为sig的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:int func(int sig);sig是传递给它的唯一参数。执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。
9、pause pause.c
(让进程暂停直到信号出现)
pause函数是让程序挂起,不退出,当捕获到信号时才根据程序逻辑退出
10、sigaction函数 sigaction.c
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
signum:信号量
act:根据信号处理相关的结构体
odlact:和上一个信号量关联的结构体
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_handler:函数指针,是关联到自定义函数或者SIG_DEF或者SIG_IGN
sa_mask:sigemptyset(&sig.sa_mask);
sa_flags:0
11、信号量集 signalset.c
#include <signal.h>
//清空信号集
int sigemptyset(sigset_t *set);
//把信号量添加到信号量集中
int sigfillset(sigset_t *set);
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how:SIG_BLOCK
set:定义并初始化信号的信号量集
odlset:NULL
12、kill() 和 raise() raise.c
kill()函数
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid:指定进程的id号
sig:SIGKILL
作用:关闭指定的进程
raise()函数
#include <signal.h>
int raise(int sig);
sig:取值SIGKILL 或 SIGSTOP
raise(SIGKILL)<=>kill(getpid(),SIGKILL)这两个功能是等价的
waitpid()函数
13、dup 和dup2
作用:文件描述符的复制,新生成的文件描述符和原来的文件描述符指向同一个文件
14、守护进程(daemon)
是长期在后台运行的程序(进程),特点是和终端断开连接
查看守护进程:
ps -efjc
ps -axj
编写守护进程规则:
1)umask
umask(0)
0002->000 000 010-> --- --- -w-
111 111 101->rwx rwx r-x
2)生成孤儿进程
pid=fork();
if(pid>0)
{
exit(0);
}
3)setsid()
让孤儿进程成为新的进程组的组长进程,成为新的会话的首领进程,并且断开和客户端的连接
4)chdir
改变守护进程的运行路经
5)关闭所有文件描述符
6)把0 1 2文件描述符关联到/dev/null
7)写系统日志
syslog()
查看系统日志的方法
cd /var/log
cat syslog
tail -10 syslog//查看最后10行
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
resource:RLIMIT_NOFILE
rlim:传地址
返回值:成功返回0出错返回-1
struct rlimit {
rlim_t rlim_cur; /* Soft limit */
rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */
};
if(rlim_max<RLIM_INFINITY)
{
rlim_max=1024;
}
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
ident:指定进程的名字
option:LOG_CONS
facility:LOG_DAEMON
void syslog(int priority, const char *format, ...);
priority:LOG_ERR
void closelog(void);
15.线程
线程是系统运行的最小单位
进程和线程的区别:
进程是系统分配资源的最小单位,线程是系统运行的最小单位,多个进程之间资源,堆栈是相互独立的,多个线程是属于一个进程的,多个线程是共享进程
资源和堆栈的
对于父子进程,父进程或子进程退出,并不影响另一个进程的运行;但是对于多线程,如果主线程先退出,其他的子线程也会退出,但子线程退出不会影响
主线程的运行
现在的线程:
现在的线程是NPTL模型的,一个任务对应一个线程
16.生成线程的函数
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread:传地址,线程tid
attr:线程的属性,NULL是缺省属性
start_routine:线程关联函数
arg:线程关联函数对应的参数
返回值:成功0出错-1
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
是阻赛函数,在主线程中调用,等待子线程的退出
thread:线程的id号
retval:子线程的退出状态
返回值:成功0
#include <pthread.h>
void pthread_exit(void *retval);
线程关联函数的退出函数
retval:线程的退出状态信息
#include <pthread.h>
pthread_t pthread_self(void);
获取线程的pid类似于getpid()
编译多线程程序需要关联一个线程代码库 -lpthread
多进程程序是并发多线程程序也是并发
=================================================day04============================================
线程之间共享资源主线程退出子线程也会退出
1、操作系统的并发和竟态
多用户多任务的时候,在同时运行,是并发,如果并发的程序访问共享变量,称为竟态;如果不保证竟态正确运行就会出现数据错乱的问题
2、怎么保证操作系统的并发和竟态
同步:工厂的生产线,同步是合作关系存在着依赖,不是竞争关系
互斥:打印机,互斥不是合作关系,存在着争抢,是竞争关系
3、临界资源
系统或网络的共享资源,比如打印机,磁盘的共享数据,内存的共享数据
4、临界区
访问临界资源的代码称为临界区
进入临界区
访问临界区
退出临界区
5、死锁
比如,有资源R1,R2;有进程P1,P2;如果P1申请了R1,P2申请了R2,此时进程不能运行,P1还需要申请R2,P2还要申请R1,但是P1占着R1不释放,P2占着R2不释放;这种现象称为死锁.
6、活锁
也是死锁的一种,活锁是一直运行一个不可能为真的条件,
7、饥饿
如果T1先申请资源,但是T2的优先级高先运行了,T1等待,本来T2运行完应该T1运行,但是T3的优先级比T1高,T3运行,一次类推,T1可能长时间的不到运行,T1处于饥饿状态
避免饥饿状态的方法:先来先服务
=================================================day05======================================
1、PV原语
PV原语是荷兰数学家迪杰斯特拉提出的,PV原语是原子操作,是不可以被中断的,PV原语是成对出现的,一个P操作一个V操作,P操作是--操作,资源数减1,v操作是++操作,资源数加1.PV原语对应2函数,但不是说这两个操作是p()和v(),不同的代码函数有不同的函数名字。比如sem_wait() P操作 sem_post() v操作
2、PV原语信号量
1)信号量是一个非负整数
semaphore sem;
2)p操作,--
sem--;
if(sem<0)
{
wait();//--
}
3)v操作,++
sem++;
if(sem<=0)//当资源数小于任务时,3个资源,5个任务,并发运行,三个任务运行后其他两个任务再申请资源的话sem就会小于0 这里sem减到
{
post();//++
}
1)5个资源,3个任务,并发运行,一个任务一个资源
2)3个资源,5个任务,并发运行
3、线程间通信-同步
sem_t sem;
sem_init();
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:初始化的信号量
sphared:0是线程间使用,非0是进程间使用
value:是初始化信号量的初值
返回值:0成功,-1错误
sem_wait();//用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少
#include <semaphore.h>
int sem_wait(sem_t *sem);
--操作
sem_post();//用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。
#include <semaphore.h>
int sem_post(sem_t *sem);
++操作
两个线程和sem: 一个线程是生产者一个线程是消费者 商品个数就是sem,生产者生产商品sem++,消费者买商品sem--,
商品为0的时候若生产者不生产商品(int sem_post(sem_t *sem);)消费者就买不到商品(int sem_wait(sem_t *sem);阻赛住了) thread_sync.c
4、线程间通信-互斥
使用的方法是互斥锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL);//一般初始化为空
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
5、进程程间通信-无名管道
pipe()
#include <unistd.h>
int pipe(int pipefd[2]);
pipe函数运行一次生成两个文件描述符;
无名管道只使用在具有亲缘关系(fork)的父子进程之间的通信
int fd[2];
fd[0]固定用于读,fd[1]固定用于写
无名管道是特殊的文件,只能使用read和write读写;
读之前需要关闭写,写之前需要关闭读
6、进程程间通信-有名管道
有名管道使用在不具有亲缘关系的父子进程之间
生成有名管道的函数:mkfifo()
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
pathname:文件名
mode:0644
返回值:成功0,错误-1
读写有名管道的函数是使用read,write函数
================================================day06==================================================
cp ../day05/common.h . mv * ../shm将当前目录下的所有文件全部拷贝到上级目录的shm目录下
1、共享内存
在内存中开辟一块空间(结构体大小),2个进程通过这个共享内存通信;共享内存是进程间通信效率最高的方式
1) #include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
key:需要指定一个固定的值
size:事先定义好的结构体大小
shmflg:IPC_CREATE
返回值:正确返回有效的ID错误返回-1
2)映射到进程内存空间
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:shmget的返回值
shmaddr:一般是NULL,进程自动把共享内存映射到进程空间
shmflg:SHM_RDONLY只读,0是可读写
返回值:成功返回映射的共享内存的地址,错误返回(void*)-1
3)撤销进程空间的内存的映射
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmaddr:映射的共享内存地址
返回值:成功返回0错误返回-1
4)删除共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:shmget的返回值
cmd:IPC_RMID(删除) IPC_STAT(查看状态) IPC_INFO(共享内存的信息)
buf:NULL
返回值:成功返回0,错误返回-1
2、消息队列
内存中生成一个消息队列(链表),3个进程读写这个队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
1) int msgget(key_t key, int msgflg); //生成
key:0x1234
msgflg:IPC_CREAT
返回值:成功返回消息队列的id,错误返回-1
2) int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); //发送
msqid:msgget的返回值
msgp:定义好的结构体
msgsz:不是整个结构体的长度,是结构体中存储消息的数组长度
msgflg:IPC_NOWAIT是不阻赛,0是阻赛
返回值:失败返回-1,成功返回0
3) ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg); //接收
msgid:msgget的返回值
msgp:结构体的地址
msgsz:存储消息的数组长度
msgtyp:接收的消息类型,1L,3L...
0:接收消息队列的第一个消息
>0:接收值相等的消息
<0:接收小于等于这个绝对值的最小的消息
msgflg:IPC_NOWAIT ,0
返回值:成功返回正确接收的字节数,错误返回-1
4) int msgctl(int msqid, int cmd, struct msqid_ds *buf); //删除
msgid:msgget的返回值
cmd:IPC_RMID
buf:NULL
返回值:错误返回-1,成功返回0
3、总结进程间通信方式
1)无名管道
2)有名管道
3)共享内存
4)消息队列(以上4种是同一个电脑间进程通信方法)
5)socket:是不同电脑间进程通信的方法
共享内存是进程间通信效率最高的方法
4、3个典型的PV原语
1)生产者-消费者
有两个生产者,两个消费者,有一个生产缓冲区,长度是15,生产者在生产产品,放入缓冲区,消费者在消费产品,从缓冲区中取出产品消费;
两个临界条件:当缓冲区满的时候生产者停止生产,当缓冲区空的时候消费者停止消费
2)哲学家就餐
5个哲学家,围坐在一个圆桌周围,每个哲学家左边放了一根筷子,共5根筷子,平时哲学家在思考,吃饭的时候,只有同时拿起左边和右边筷子的
哲学家才可以吃饭;临界条件(竞争条件):都同时拿起了左边或右边的一根筷子,都不能吃饭
解决方法:允许最多只有4个哲学家同时拿起左边的筷子
3)读者学者
m个读者n个写者,读者在读,写者在写,需要满足规定:读者可以同时读,写者不可以同时写,也不可以同时读写
5、系统编程总结
系统概述
*标准文件IO
*系统文件IO
*进程 fork()
僵尸进程 孤儿进程 守护进程 信号量 信号量集
*线程
线程间通信
进程间通信
3个PV原语
***************************************************网络编程*******************************************
网络概述
6、什么是网络
网络是一组自治的计算机,通过交换机和路由器把计算机连起来,收发数据,通信
7、网络分类
局域网:
以太网(主流) 令牌环网(过时) 光纤网(主干网) ATM(曾今是主流)
城域网:
多个以太网城域网
广域网:
多个城域网组成广域网
8、网络的传输介质
双绞线:网线
wifi:大气电磁波
同轴电缆:曾今很主流,曾今的主干网用的很多
光纤:单模光纤(一条信号) 多模光纤(多条信号)
光传输:借助光速传输信号
9、网络传输数据的格式
电路交换:过去的制式电话,模拟信号
报文交换:现在的数字电话,数据计算机,数字信号
分组交换:当报文长度过长时,需要把报文分成几部分
模拟信号:是正弦或余弦波形
数字信号:是离散的数据
最初都是模拟电路,后来有了大规模集成电路,形成了数字芯片,逻辑门,就有了数字电路
不管是模拟电路还是数字电路,最后在线路上传输的都是电信号,高电平或者低电平
10、网络设备
HUB:网络流量分流的设备,一分多,平均的过程
中继器:是网络信号的再生和还原设备