系统编程学习笔记

=========================================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:网络流量分流的设备,一分多,平均的过程
中继器:是网络信号的再生和还原设备
 

 

    

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值