复习

作者: oliver__ | 来源:发表于2017-04-11 21:54 被阅读20次

    第一章: 1.linux系统架构

    QQ截图20171120080445.png
                application  应用程序
    

                系统接口(系统调用、C库函数、其它库函数(图片压缩、转换)
    

    操作系统: 进程管理、内存管理、设备管理、文件管理、网络管理
    

            设备驱动(字符型设备驱动、块设备驱动、网络设备驱动)
    

            硬件(键盘、鼠标、显示器、硬盘、内存、USB、串口)
    
    2.错误处理函数
        errno  一个整数、标志当前内核中的错语的一个整数
        perror 打印当前程序的错语信息(自动根据系统的errno来区分当前到底是哪一个错误)
        strerror 用于把一个errno转换成对应的错语的描述字符串
    

    strerror.c 包含头文件<errno.h> 把 int的整数转换成字符串 man error

    
    #include <stdio.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    int main(void)
    {
        if(open("1.txt", O_RDONLY) < 0)
        {
            //printf("%d\n", errno);
            printf("%s\n", strerror(errno));
            perror("open");
        }
    
        return 0;
    }
    

    第三章: 对文件的数据进行读写

    
    
    linux的文件IO(不带缓冲的文件IO、open家族的文件IO)
            open 打开或者创建文件,返回的是一个文件描述符
                0:代表标准输入(键盘)
                1:标准输出(显示器)
                2:标准出错(显示器)
                    int open(const char *pathname, int flags);
                    int open(const char *pathname, int flags, mode_t mode);
            flags:   O_RDONLY:只读的方式打开文件
                     O_WRONLY:只写方式打开文件
                     O_RDWR:读写方式打开文件
                     O_APPEND:追加的方式打开文件
                     O_CREAT:  如果文件不存在,就创建
                     O_TRUNC:  如果文件存在就清0
                     O_NONBLOCK: 以非阻塞的方式打开文件(字符型设备有效)
                     O_SYNC:每次写入数据到文件、都会等待直到数据真正的写到磁盘中才会继续向下运行
            mode:代表文件被创建的权限,一般用八进制整数表示0777 0666 0644
    
            read:读文件
            write:写文件
            close:关闭一个打开的文件
    open write sync 函数
    
     
    
    

    open.c 第一个参数是文件名字 第二个参数: 读|创建 返回一个文件描述符

    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    struct task
    {
        int id; 
        char file[64];
        int threadnum;
        int filesize;
    };
    
    struct task t = {
        1, "1.dat", 5, 1024 * 1024,
    };
    int main(void)
    {
        //以读写方式打开文件、如果不存在就创建
        int fd = open("1.dat", O_RDWR | O_CREAT, 0777);
        if(fd < 0)
        {
            perror("open");
            return -1;
        }
    
        //把数据写入到文件中
        int ret = write(fd, &t, sizeof(t));
        if(ret != sizeof(t))
        {
            perror("write");
            return -1;
        }
    
        //把文件指针移动到文件首
        lseek(fd, 0, SEEK_SET);
    
        //从文件中读取数据
        struct task tmp;        
        ret = read(fd, &tmp, sizeof(tmp));
        if(ret == sizeof(tmp))  
        {
            printf("%d %s %d %d\n", tmp.id, tmp.file, tmp.threadnum, tmp.filesize);
        }
    
        close(fd);
        return 0;
    }
    
    
    
    
    
    
    
    
    
    
    
        文件的下载:任务 文件名 线程 文件大小
        把数据写入到文件中, 以二进制形式写入 write第一个参数: 文件描述符  第二个:地址 
    
            lseek:移动文件指针
                SEEK_SET  文件首
                SEEK_CUR  文件指针当前位置
                SEEK_END  文件尾
            fsync:把缓存在磁盘队列中的数据刷新到磁盘中
            fdopen:  把一个文件描述符转换成FILE类型的指针  int fd-->FILE *fp
            fileno:  把一个FILE *fp转换成一个文件描述符fd  FILE *fp ---> int fd
    

    write.c

    Wirte 函数  不带缓冲的
    printf带缓冲的文件IO
    
    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
        //write(1, "hello", strlen("hello")); //不带缓冲的文件IO
        printf("hello");//带缓冲的文件IO
        sleep(10);
        //write(1, "world", strlen("world"));
        printf("world");
    
        return 0;
    }
    
    

    第四章:对文件的属性进行操作(大小、权限、拥有者)、目录

    stat.c()

    stat参数: 文件属性,地址
            文件大小st.st_size  
            文件类型  S_ISREG(st.st_mode)
                        S_I     目录的大小是4k
    
    
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    int main(void)
    {
        struct stat st;
    
        //获取文件属性
        //stat("1.dat", &st);
        //stat("/", &st);
        //stat("/dev/input/mouse0", &st);
    
        int fd = open("1.dat", O_RDONLY);
        fstat(fd, &st);
    
        printf("文件大小:%ld\n", st.st_size);
    
        if(S_ISREG(st.st_mode))
        {
            printf("这是一个普通文件\n");
        }
        else if(S_ISDIR(st.st_mode))
        {
            printf("这是一个目录文件\n");
        }
        else if(S_ISCHR(st.st_mode))
        {
            printf("这是一个字符设备文件\n");
        }
    
        return 0;
    }
    fsata是传递文件描述符(文件已经打开)
    
    
    1.stat、fstat 获取一个文件的I结点信息(属性)
             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 file system 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 */
               };
            获取文件类型:
               S_ISREG(m)  is it a regular file?
               S_ISDIR(m)  directory?
               S_ISCHR(m)  character device?
               S_ISBLK(m)  block device?
               S_ISFIFO(m) FIFO (named pipe)?
               S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
               S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
    
    
    

    fileno.c

    
        fileno把一个FILE类型指针转换成一个文件描述符
            strlen是获取字符串的大小
            sizeof是获取字符串占据空间的大小
            fpopen把一个文件描述符转换成file类型指针
    
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    int main(void)
    {
        FILE *fp;
    
        fp = fopen("2.txt", "w");
        if(fp == NULL)
        {
            perror("fopen");
            return -1;
        }
    
        //把一个FILE *转换成一个文件描述符
        int fd = fileno(fp);
    
        write(fd, "hello", strlen("hello"));
        //write(fd, "hello", sizeof("hello"));
    
        struct stat st;
        fstat(fd, &st);
        printf("%d\n", st.st_size);
    
        return 0;
    }
    

    演示函数fdopen.c

    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(void)
    {
        int fd = open("2.txt", O_RDONLY);
        if(fd < 0)
        {
            perror("open");
            return -1;
        }
    
        FILE *fp;
        fp = fdopen(fd, "r"); //把一个文件描述符转换成一个FILE类型的指针
        if(fp == NULL)
        {
            perror("fdopen");
            return -1;
        }
    
        char buf[100] = {0};
        fgets(buf, sizeof(buf), fp);
        printf("%s\n", buf);
    
        fclose(fp);
        return 0;
    }
    
    
    
    
    
    
    
            fgets读取数据
    lsata获取软链接文件
    
        2.access判断一个文件是否存在、是否可读、是否可写、是否可执行
            R_OK是否可读
            W_OK是否可写
            X_OK是否可执行
            F_OK是否存在
    
    

    access.c

            access(… … )      F_OK这个文件是否存在  等于0表示存在
    
    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
        //判断一个文件是否存在
        int ret = access("2.txt", F_OK);
        if(ret == 0)
        {
            printf("这个文件存在\n");
        }
        else
        {
            printf("这个文件不存在\n");
        }
    
        return 0;
    }
    
    
    
        3.umask修改进程创建文件的屏蔽字
    
    

    umas.c umask()函数先取反,再与操作

        一,创建文件
          remove()删除文件函数
        二,获取文件属性  st.st_mode 获取文件低九位
    
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(void)
    {
        struct stat st;
    
        //修改文件屏蔽字
        umask(033);
    
        //如果这个文件存在,就删除
        if(access("3", F_OK) == 0)
        {
            remove("3");
        }
    
        //创建这个文件,以0777的方式创建
        int fd = open("3", O_RDONLY | O_CREAT, 0777);
        if(fd < 0)
        {
            perror("open");
            return -1;
        }
    
        //获取这个文件的属性
        fstat(fd, &st);
        printf("文件的权限是%o\n", st.st_mode & 0x1ff);
        return 0;
    }
    
    
    
    
    
    
    
    
        4.修改文件长度 truncate    ftruncate
    
    

    truncate.c 修改文件大小

            参数: 文件名字 文件大小
            用于多线程下载
    
    #include <unistd.h>
    #include <sys/types.h>
    
    int main(void)
    {
        //修改文件大小
        truncate("1.txt", 1024 * 1024 * 400);
    
        return 0;
    }
    
    
    
        5.unlink  删除一个文件
        
    

    unlink.c access(1.dat F_OK)=0 判断文件存在

            unlink()
    
    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
        if(access("1.dat", F_OK) == 0)
        {
            printf("删除前存在1.dat\n");
        }
        else
        {
            printf("删除前不存在1.dat\n");
        }
    
        //删除文件
        //unlink("1.dat");
        remove("1.dat");
    
        if(access("1.dat", F_OK) == 0)
        {
            printf("删除后存在1.dat\n");
        }
        else
        {
            printf("删除后不存在1.dat\n");
        }
    
        return 0;
    }
    
    
    
          rmdir  删除一个空目录
          remove 删除一个文件或者一个空目录
        6.mkdir 创建目录
        
    

    mkdir.c

    
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    
    int main(void)
    {
        //创建一个叫aaa的目录
        mkdir("aaa", 0777);
    
        return 0;
    }
    
    
    
        7.opendir  readdir  closedir  rewinddir  打开目录、读取目录项、关闭目录
    
    

    opendir.c man 3 dir 读取目录下的文件 目录的递归操作

    
    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    
    int main(void)
    {
        //打开目录          
        DIR *dir = opendir("/");
        if(dir == NULL)
        {
            perror("opendir");
            return -1;
        }
    
        struct dirent *dent;
        while(1)
        {
            dent = readdir(dir); //读取目录的一项数据
            if(dent != NULL)
            {
                printf("%s\n", dent->d_name);
            }
            else
                break;
        }
    
        closedir(dir);
        return 0;
    }
    
    
    
        8.getcwd  获取当前工作路径
    
    

    getcwd.c getwcd返回一个当前工作路径

    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
        char buf[100] = {0};
        //printf("当前工作路径是%s\n", getcwd(NULL, 0));
        printf("当前工作路径是%s\n", getcwd(buf, sizeof(buf)));
        printf("当前工作路径是%s\n", buf);
    
        //修改当前工作路径
        chdir("/opt");
        printf("当前工作路径是%s\n", getcwd(buf, sizeof(buf)));
        printf("当前工作路径是%s\n", buf);
    
        return 0;
    }
    
    
    
        9.chdir   修改当前工作路径
    

    第六章:

    1.   密码文件的读取  /etc/passwd   存放的是用户的信息
            getpwnam  根据用户名获取用户信息
            getpwuid  根据用户ID获取用户信息
            getpwent  从/etc/passwd文件中读取一行数据
    
    
    

    getpwname.c

    
            shell 中false是完全不能使用的
            getpwname()函数返回一个结构体 struct passed
    
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <pwd.h>
    
    int main(void)
    {
        struct passwd *pw = NULL;
        //pw = getpwnam("root");
        pw = getpwuid(1);
        if(pw == NULL)
        {
            perror("getpwnam");
        }
        else
        {
            printf("%s:%s:%d:%d:%s:%s:%s\n", pw->pw_name, 
                    pw->pw_passwd, 
                    pw->pw_uid, 
                    pw->pw_gid, 
                    pw->pw_gecos, 
                    pw->pw_dir, 
                    pw->pw_shell);
        }
    
        return 0;
    }
    
    
    2.   阴影文件的读取  /etc/shadow   存放的是用户的密码相关的信息
            getspnam  根据用户名获取这个用户的密码相关的信息
            getspent
    

    getspname.c 获取用户密码

    #include <shadow.h>
    #include <stdio.h>
    
    int main(void)
    {
        struct spwd *sp = getspnam("root");
        if(sp == NULL)      
        {
            perror("getspnam");
        }
        else
        {
            printf("%s\n", sp->sp_pwdp);
        }
    
        return 0;
    }
    
    
    3.时间相关的函数
        time   获取一个从1970.1.1 0:0:0到当前一个秒数
        gettimeofday   获取一个更精确的时间(微秒)
        settimeofday   设置系统的当前时间
        ctime  把一个time转换成字符串表示的年月日时分秒
        asctime  把一个struct tm的结构体转换成字符串的年月日时分秒
        localtime  获得一个年月日时分秒的结构体(本地时间)
        gmtime  获得一个年月日时分秒的结构体(全球时间)
        mktime  把一个struct tm的结构体转换成time_t的秒数
    

    time.c

    
    #include <stdio.h>
    #include <time.h>
    
    int main(void)
    {
        printf("当前时间是%d\n", time(NULL));
    
        time_t t;
    
        time(&t);
        printf("当前时间是%d\n", (int)t);
    
        return 0;
    }
    
    

    ctime.c

    
    #include <stdio.h>
    #include <time.h>
    
    int main(void)
    {
        time_t t;
    
        time(&t);
        printf("当前时间是%d %s\n", (int)t, ctime(&t));
    
        return 0;
    }
    
    

    localtime.c gmtime(全球时间)

    settime()(设置时间)     需要加sudo
    
    #include <stdio.h>
    #include <time.h>
    
    int main(void)
    {
        time_t t = time(NULL);
        //struct tm *tm = localtime(&t);        
        struct tm *tm = gmtime(&t);     
        
        printf("%d年%d月%d日 %d:%d:%d\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 
                    tm->tm_hour, tm->tm_min, tm->tm_sec);
        return 0;
    }
    

    settimeofday.c 设置时间为微秒

    
    #include <stdio.h>
    #include <time.h>
    #include <sys/time.h>
    
    int main(void)
    {
        struct tm tm;
        tm.tm_sec = 30;
        tm.tm_min = 30;
        tm.tm_hour = 8;
        tm.tm_mday = 12;
        tm.tm_mon = 4;
        tm.tm_year = 2019 - 1900;
        time_t t = mktime(&tm);
        printf("%d\n", t);
    
        //printf("%s\n", ctime(&t));
        struct timeval tv;  
        tv.tv_sec = t;
        tv.tv_usec = 0;
        settimeofday(&tv, NULL);
    
        return 0;
    }
    
    

    第七章:进程入门

    1.进程正常结束:从main函数直接返回、执行exit结束
        1.关闭所有文件、刷新所有缓冲区中的数据到文件中
        2.执行进程的清理函数
    
       进程不正常结束:不会执行以上两步。被信号杀死、_exit函数结束
    
    2.进程的清理函数  atexit注册进程的清理函数
    

    atexit.c

    #include <stdlib.h>
    #include <stdio.h>
    
    void do_quit(void);
    int main(void)
    {
        //注册清理函数        
        atexit(do_quit);
    
        sleep(5);
        printf("进程结束了\n");
    
        return 0;
    }
    
    void do_quit(void)
    {
        printf("进程被清理了\n");
    }
    
    
    3.main的参数:main函数在被系统调用时、系统也是可以传递参数给main函数
        int main(int argc, char *argv[]);
        int main(int argc, char *argv[], char *env[]);
    

    mian的参数.c

        argc 指传递给main函数的命令行中字符串的个数
        argv中存放的是命令行中的字符串
    
    
    #include <stdio.h>
    
    //main的参数
    int main(int argc, char *argv[])
    {
        //argc指传递给main的命令行中字符串的个数
        //argv中存放的是命令行中的字符串
        //  ./kkk  1 2 3 ---> argc = 4  argv[0] ="./kkk" argv[1] = "1" argv[2] = "2" ....
    
        int i;
        for(i = 0; i < argc; i++)
        {
            printf("argv[%d] = %s\n", i, argv[i]);
        }
    
        return 0;
    }
    
    
    4. 进程环境变量表:
            通过main函数的第三个参数来访问
                int main(int argc, char *argv[], char *env[]);
            通过linux中定义的一个全局变量 environ来访问
    

    环境变量表.c

    声明全局变量 extern 指向系统的环境表
    
    
    #include <stdio.h>
    
    int main(int argc, char *argv[], char **env)
    {
        //声明全局变量
        //extern char **environ;    
        int i;
        //for(i = 0; environ[i] != NULL; i++)
        for(i = 0; env[i] != NULL; i++)
        {
            //printf("%s\n", environ[i]);
            printf("%s\n", env[i]);
        }
    
        return 0;
    }
    
    5. 
            获取进程的某一个环境变量   getenv
            设置进程的环境变量   setenv
    

    getenv.c 获取环境变量,可获得当前工作路径

    getcpwd()相比较

    设置进程的环境变量 setenv 修改PWD环境变量
    参数

    #include <stdlib.h>
    #include <stdio.h>
    
    int main(void)
    {
        char *pwd = getenv("PWD");
        printf("%s\n", pwd);
        printf("%s\n", getcwd(NULL, 0));
    
        chdir("/opt");
        //修改PWD环境变量
        setenv("PWD", getcwd(NULL, 0), 1);
    
        pwd = getenv("PWD");
        printf("%s\n", pwd);
        printf("%s\n", getcwd(NULL, 0));
    
        return 0;
    }
    
    
    6.  getrlimit 获取系统对资源的限制值
        setrlimit 修改系统对资源的限制值
    

    第八章:

    getpid  获取进程的PID
    getppid  获取进程的父进程的PID
    fork    创建子进程
    

    getpid.c 函数获取当前进程pid

    getppid()函数获取父进程pid

    
    #include <stdio.h>
    #include <unistd.h>
    
    int main(void)
    {
        pid_t pid;
    
        //获取当前进程ID
        pid = getpid();
    
        pid_t ppid;
        //获取当前进程父进程ID
        ppid = getppid();
    
        printf("进程ID是%d, 父进程ID是%d\n", pid, ppid);
    
        return 0;
    }
    
    

    fork.c 创建子进程

        fork()=0,子进程创建成功
        创建指针函数作为子进程,对fork进程封装
        read(0,buf,sizeof(buf))读取键盘操作
        bzero(buf,sizeof(buf)) buf清零
        读取鼠标必须先打开鼠标 mouse = open(“/dev/inout/mice, O_RDONLY”)
    
    
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(void)
    {
        int mouse;
    
        mouse = open("/dev/input/mice", O_RDONLY);
        if(mouse < 0)
        {
            perror("open");
            return -1;
        }
    
        int ret;
        char buf[100] = {0};
        if(fork() == 0) //子进程
        {
            while(1)
            {
                ret = read(0, buf, sizeof(buf));
                if(ret > 0)
                {
                    printf("键盘说:%s\n", buf);
                    bzero(buf, sizeof(buf));
                }
            }
        }
        else
        {
            while(1)
            {
                ret = read(mouse, buf, sizeof(buf));
                if(ret > 0)
                {
                    printf("mouse say: %s\n", buf);
                    bzero(buf, sizeof(buf));
                }
            }   
        }
    
        return 0;
    }
    
    
    
    
    
    
    
    
    
    
    
    

    fork2.c

    
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    //创建一个子进程/这个子进程的目的就是为了执行函数fun
    int newprocess( void (*fun)(void) )
    {
        //创建一个子进程
        if(fork() == 0) 
        {
            fun(); //在子进程中执行fun函数
            exit(0); //子进程退出
        }
    
        return 0;
    }
    
    void readmouse(void);
    int main(void)
    {
        int ret;
        char buf[100] = {0};
    
        //创建子进程用于读取鼠标
        newprocess(readmouse);
    
        while(1)    
        {
            //读取键盘
            ret = read(0, buf, sizeof(buf));
            if(ret > 0)
            {
                printf("键盘说:%s\n", buf);
                bzero(buf, sizeof(buf));
            }
        }
    }
    
    void readmouse(void)
    {
        int ret;
        int mouse;
        char buf[100] = {0};
        mouse = open("/dev/input/mice", O_RDONLY);
        if(mouse < 0)
        {
            perror("open");
            return -1;
        }
    
        while(1)    
        {
            ret = read(mouse, buf, sizeof(buf));
            if(ret > 0)
            {
                printf("mouse say:%s\n", buf);
                bzero(buf, sizeof(buf));
            }
        }
    }
    
    
    
    
    
    
    
    
    
    
    

    第十章:信号

    1.linux内核提供的一种机制、用于通知系统中的应用程序发生了某种事件
    2.kill -l这个命令来列出linux支持的信号
        SIGINT  中断信号     ctrl+c
        SIGQUIT 退出信号     ctrl+\
        SIGFPE  浮点异常     除0  
        SIGSEGV 段错误       当系统中检测到段错误发生时
    

    signal.c

    #include <stdio.h>
    #include <signal.h>
    
    int main(void)
    {
        char *ptr = NULL;
        *ptr = 10; //段错语
        
        int a = 1/0; //浮点异常
        printf("%d\n", a);
    
        printf("lksjdflksjdflksdjflskdjf\n");
        return 0;
    }
    
    
    
    3.进程收到信号后会做出三种反映:
        1. 按照默认的方式处理这个信号(每个信号都有一个默认动作)
        2. 忽略这个信号(signal(信号,SIG_IGN));
        3. 执行一个信号处理函数(signal(信号,函数));
    

    注册函数signal() 参数:SIGIGN忽略信号 第二个参数可以是个函数

    signal2.c

    
    #include <stdio.h>
    #include <signal.h>
    
    void sig_int(int sig);
    int main(void)
    {
        //忽略SIGINT信号
    //  signal(SIGINT, SIG_IGN);
    
        //注册SIGINT的信号处理函数
        signal(SIGINT, sig_int);
    
        while(1)
        {
            sleep(1);
            printf("i am running\n");
        }
    
        return 0;
    }
    
    void sig_int(int sig)
    {
        printf("sigint产生了\n");
    }
    
    
    
    
    
    
    4.  kill  发出信号
        raise 产生一个信号(发送一个信号给自己)
        alarm 设置一个定时器,时间到来后会自动发出SIGALRM信号
        pause 让进程暂停下来、可以被任意信号唤醒
        abort 产生一个SIGABRT的信号  (用于终止进程、不正常终止)
    

    kill.c 发送一个信号

    
    #include <sys/types.h>
    #include <signal.h>
    
    //kill 发送一个信号
    int main(void)
    {
        //创建子进程
        if(fork() == 0)     
        {
            int count = 5;
            while(count > 0)
            {
                count--;
                printf("距离下班还有%d秒\n", count);
                sleep(1);
            }
    
            printf("下班了\n");
            kill(getppid(), SIGINT); //发送一个SIGINT信号给父进程
            exit(0);
        }
        else
        {
            while(1)
            {
                printf("我是父进程,,,我还有上班\n");
                sleep(1);
            }
        }
    
        return 0;
    }
    
    

    定时器信号. alarm()函数, 产生信号 进程默认退出

    pause()函数 产生暂停信号,直到另一个信号产生.
    

    alarm.c

    
    #include <stdio.h>
    
    int main(void)
    {
        printf("程序将在5秒后结束\n");
    
        //5秒之后自动发出SIGALRM信号
        alarm(5);
    
        pause(); //程序暂停了
    
    #if 0
        while(1)
        {
            ;;;;;
        }
    #endif
    
        return 0;
    }
    
    

    sleep.c signal()防止进程被信号杀死

    
    #include <stdio.h>
    #include <signal.h>
    
    void sig_proc(int sig);
    int main(void)
    {
        //signal(SIGALRM, SIG_IGN);
        signal(SIGALRM, sig_proc);
    
        alarm(5);
    
        printf("程序开始睡30秒\n");
        sleep(30);
        printf("程序退出\n");
    
        return 0;
    }
    
    void sig_proc(int sig)
    {
        printf("sig\n");
    }
    
    
    

    第十一章:线程:

    pthread_create:创建一个线程
    pthread_self:获取线程的ID
    pthread_join:等待其它线程结束(回收线程的资源)
    pthread_cancel 通知一个线程结束
    pthread_cleanup_push  为线程注册清理函数 
    pthread_cleanup_pop
    

    pthread_create.c 线程的封装

        编译的时候要链接线程库 -lpthread
        设置信号处理函数signal()
        通知一个线程结束 pthread_cancel  得先拿到线程的id号
        然后等待线程结束 pthread_join
        为线程注册清理函数 pthread_cleanup_push() 参数 :执行一个清理函数  arg
        必须调用pthread_cleanup_pop(1)函数
    
    
    #include <pthread.h>
    #include <stdio.h>
    #include <signal.h>
    
    int quit = 0;
    void sig_quit(int sig);
    void thread_quit(void *arg);
    void *do_playmusic(void *arg);
    int main(void)
    {
        pthread_t tid[3];
        signal(SIGINT, sig_quit);
    
        //创建一个线程
        pthread_create(&tid[0], NULL, do_playmusic, (void *)"李香兰"); 
        pthread_create(&tid[1], NULL, do_playmusic, (void *)"霸王别姬");    
        pthread_create(&tid[2], NULL, do_playmusic, (void *)"北京北京");    
    
        while(quit == 0)
        {
            printf("打印----\n");
            sleep(1);
        }
    
        int i;
        for(i = 0; i < 3; i++)      
        {
            //通知这个线程退出
            pthread_cancel(tid[i]);
            //等待这个线程退出
            pthread_join(tid[i], NULL);
        }
    
        return 0;
    }
    
    void sig_quit(int sig)
    {
        quit = 1;
    }
    
    void *do_playmusic(void *arg)
    {
        char *music = arg;
        //为线程注册清理函数
        pthread_cleanup_push(thread_quit, arg);
    
        while(1)
        {
            printf("播放音乐---%s\n", music);
            sleep(1);
        }
    
        pthread_cleanup_pop(1);
    }
    
    void thread_quit(void *arg)
    {
        printf("%s被清理了\n", (char *)arg);
    }
    
    
    
    

    ==2017年3月2日11:27:20==

    同步与互斥:
    互斥锁:用于实现多个线程对同一个资源的访问是原子性
    pthread_mutex_init
    pthread_mutex_destroy
    pthread_mutex_lock
    pthread_mutex_unlock
    int pthread_setcancelstate(int state, int *oldstate);
    int pthread_setcanceltype(int type, int *oldtype);

    创建互斥锁pthread_mutex.c

        先进行初始化
        用完之后进行解散
        最后要进行销毁
    缺点:效率比不佳锁低
        可能多个线程一起使用一个变量
        nanaosleep() 睡眠纳米级
    有可能线程在锁的时候被通知取消。因此要取消线程的状态
    
    如果一个锁加两次,就会出现死锁现象
    
    
    #include <stdio.h>
    #include <signal.h>
    #include <pthread.h>
    #include <time.h>
    
    int quit = 0;
    int tick = 0;
    pthread_mutex_t mutex;
    void sig_quit(int sig);
    void *thread(void *arg);
    int main(void)
    {
        int i;
        pthread_t tids[100];
    
        signal(SIGINT, sig_quit);
    
        pthread_mutex_init(&mutex, NULL);
    
        for(i = 0; i < 100; i++)    
        {
            pthread_create(&tids[i], NULL, thread, NULL);
        }
    
        while(quit == 0)
        {
            pause();    
        }
    
        for(i = 0; i < 100; i++)
        {
            pthread_cancel(tids[i]);
            pthread_join(tids[i], NULL);
        }
    
        pthread_mutex_destroy(&mutex);
    
        return 0;
    }
    
    void *thread(void *arg)
    {
        struct timespec t;
    
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    
        while(1)
        {
            //加两次锁会导致死锁
            pthread_mutex_lock(&mutex); //加锁
            //pthread_mutex_lock(&mutex); //加锁
            tick++;
            t.tv_sec = 0;
            t.tv_nsec = 10;
            nanosleep(&t, NULL);
            printf("tick = %d\n", tick);
            //pthread_mutex_unlock(&mutex); //解锁
            pthread_mutex_unlock(&mutex); //解锁
        }
    }
    
    void sig_quit(int sig)
    {
        quit = 1;
    }
    
    
        如何防止死锁:1. 所有的锁只能加一次
                     2. 加锁顺序要一致
                
        读写锁:
            读锁与读锁之间是不互斥的
            读锁与写锁是互斥的
            写锁与写锁是互斥的
            pthread_rwlock_init
            pthread_rwlock_destroy
            pthread_rwlock_rdlock
            pthread_rwlock_wrlock
            pthread_rwlock_unlock
    
        条件变量:解决生产者与消费者之间同步的问题
            pthread_cond_init
            pthread_cond_destroy
            pthread_cond_wait   让线程等待条件满足
            pthread_cond_signal 通知等待的线程继续运行
            pthread_cond_broadcast   通知所有等待的线程继续运行
    

    第十四章:高级IO
    1. 非阻塞型IO
    对于一些低速设备,linux对它们的读写操作使用的是阻塞型机制(由这些设备的驱动来决定的)。

    block.c 阻塞型设备:如鼠标键盘,网络

            fcntl() 以键盘为例把键盘设置为非阻塞
                    例:把键盘输入与 socket消息
    
    
    #include <stdio.h>
    #include <unistd.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    int main(void)
    {
        int ret;
        char buf[100];
    
        //把键盘设置为非阻塞
        fcntl(0, F_SETFL, O_NONBLOCK);
    
        while(1)
        {
            //阻塞型:如果没有数据可读,会阻塞,直到有数据可读为址
            ret = read(0, buf, sizeof(buf)); 
            if(ret > 0) 
            {
                printf("%s\n", buf);
            }
            else
            {
                printf("没有数据\n");
                sleep(1);
            }
        }
    
        return 0;
    }
    
    
    2. 把一个阻塞型的设备以非阻塞的方式进行读写操作
          以键盘为例:
            int fcntl(int fd, int cmd, ... /* arg */ );
            fcntl(0, F_SETFL, O_NONBLOCK);
    
    3. 一个程序中同时要读写两个以上的阻塞型设备、此时可以采用IO多路转换的方式
            poll
            select
    
    4. 异步IO机制
          1.  把设备设置为异步方式
                fcntl(fd, F_SETFL, O_ASYNC);
    
          2.  把进程的PID告诉给设备驱动
                fcntl(fd, F_SETOWN, getpid());
    
          3.  设置进程对SIGIO信号的处理函数
                signal(SIGIO, procdat); //procdat是一个函数,用于读取设备数据
    

    第十五章:进程间通信

    1.无名管道:只能用于有亲缘关系的进程之间的通信
        pipe
        它是一种单双工的通信
    

    管道pipe.c

        无名pipe()  创建一个管道int fd=1,单双通,亲缘之间的通讯
    
    
    #include <stdio.h>
    
    int main(void)
    {
        int fd[2];
        char buf[100] = {0};
    
        //创建一个无名管道
        pipe(fd);
    
        if(fork() == 0) //创建一个子进程
        {
            //子进程把数据写入到管道的写端
            write(fd[1], "hello", strlen("hello"));
        }
        else
        {
            //父进程
            read(fd[0], buf, sizeof(buf));
            printf("%s\n", buf);
        }
    }
    
    
    2.命名管道:能用于任意的两个进程之间的通信
        mkfifo
        它是一种单双工的通信
    

    mkdir fifo

    #### fifo1.c    fifo2.c
        mkfifo()函数创建管道文件   
            协同作用,你一句我一句(读取管道和键盘阻塞)
        打开读管道open(RFIFO, RDONLY)
    
    ### poll.c监听机制  poll() 参数 监听个数 -1  函数中有结构体{   }
        selet机制
    
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <poll.h>
    
    #define RFIFO "rfifo"
    #define WFIFO "wfifo"
    int main(void)
    {
        int ret;
        char buf[100];
    
        //创建管道
        mkfifo(RFIFO, 0777);
        mkfifo(WFIFO, 0777);
    
        int rfd, wfd;   
    
        //打开RFIFO管道的读端
        rfd = open(RFIFO, O_RDONLY);
        if(rfd < 0)
        {
            perror("open");
            return -1;
        }
    
        //打开WFIFO管道的写端
        wfd = open(WFIFO, O_WRONLY);
        if(wfd < 0)
        {
            perror("open");
            return -1;
        }
    
    //  fcntl(0, F_SETFL, O_NONBLOCK);
    //  fcntl(rfd, F_SETFL, O_NONBLOCK);
        struct pollfd pfd[2];
        pfd[0].fd = 0;
        pfd[1].fd = rfd;
        pfd[0].events = POLLIN;
        pfd[1].events = POLLIN;
        while(1)
        {
            //监听0与rfd是否可读
            if(poll(pfd, 2, -1) > 0)
            {
                if(pfd[0].revents == POLLIN)    
                {
                    //读键盘
                    bzero(buf, sizeof(buf));
                    ret = read(0, buf, sizeof(buf)); //阻塞
                    if(ret > 0)
                    {
                        //把数据写入到WFIFO的写端
                        write(wfd, buf, ret);
                    }
                }
    
                if(pfd[1].revents == POLLIN)
                {
                    //读管道RFIFO
                    bzero(buf, sizeof(buf));
                    ret = read(rfd, buf, sizeof(buf)); //阻塞
                    if(ret > 0)
                    {
                        printf("fifo2说:%s\n", buf);
                    }
                }
            }
        }
        
        return 0;
    }
    
    

    fifo2.c

    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <poll.h>
    
    #define RFIFO "rfifo"
    #define WFIFO "wfifo"
    int main(void)
    {
        int ret;
        char buf[100];
    
        //创建管道
        mkfifo(RFIFO, 0777);
        mkfifo(WFIFO, 0777);
    
        int rfd, wfd;   
    
        //打开RFIFO管道的写端
        wfd = open(RFIFO, O_WRONLY);
        if(wfd < 0)
        {
            perror("open");
            return -1;
        }
    
        rfd = open(WFIFO, O_RDONLY);
        if(rfd < 0)
        {
            perror("open");
            return -1;
        }
    
        struct pollfd pfd[2];
        pfd[0].fd = 0;
        pfd[1].fd = rfd;
        pfd[0].events = POLLIN;
        pfd[1].events = POLLIN;
        while(1)
        {
            //监听0与rfd是否可读
            if(poll(pfd, 2, -1) > 0)
            {
                if(pfd[0].revents == POLLIN)    
                {
                    //读键盘
                    bzero(buf, sizeof(buf));
                    ret = read(0, buf, sizeof(buf)); //阻塞
                    if(ret > 0)
                    {
                        //把数据写入到WFIFO的写端
                        write(wfd, buf, ret);
                    }
                }
    
                if(pfd[1].revents == POLLIN)
                {
                    //读管道RFIFO
                    bzero(buf, sizeof(buf));
                    ret = read(rfd, buf, sizeof(buf)); //阻塞
                    if(ret > 0)
                    {
                        printf("fifo2说:%s\n", buf);
                    }
                }
            }
        }
        
        return 0;
    }
    
    

    3.消息队列

            ftok    通过一个文件来生成一个key
            msgget  创建消息队列
            msgrcv  从消息队列中取消息
            msgsnd  把消息发送到消息队列中
            msgctl  对消息队列进行操作(销毁、设置)
    

    msgsnd.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    #define MSGFILE "msgfile"
    struct msgbuf {
        long mtype;       /* message type, must be > 0 */
        char mtext[100];    /* message data */
    };
    
    struct student
    {
        int age;
        char name[20];
    };
    
    int main(void)
    {
        //创建msgfile这个文件 
        close(open(MSGFILE, O_RDONLY | O_CREAT, 0777));
    
        //根据msgfile生成一个key
        key_t key = ftok(MSGFILE, 1);
    
        //创建消息队列
        int msgid = msgget(key, IPC_CREAT | 0777);
        if(msgid == -1)
        {
            perror("msgget");
            return -1;
        }
    
    //  int a = 30;
        struct msgbuf  msg;
        msg.mtype = 1;
        //strcpy(msg.mtext, "lsdjflksdjflkdsjflskdjf");
    //  memcpy(msg.mtext, &a, sizeof(a));
    
        struct student stu = {
            20, "aaa"
        };
        memcpy(msg.mtext, &stu, sizeof(stu));
    
        //向消息队列中发送消息
        //msgsnd(msgid, &msg, strlen(msg.mtext), 0);
        //msgsnd(msgid, &msg, sizeof(a), 0);
        msgsnd(msgid, &msg, sizeof(stu), 0);
    
        return 0;
    }
    

    msgrcv.c

    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    #define MSGFILE "msgfile"
    struct msgbuf {
        long mtype;       /* message type, must be > 0 */
        char mtext[100];    /* message data */
    };
    
    struct student
    {
        int age;
        char name[20];
    };
    
    int main(void)
    {
        //创建msgfile这个文件 
        close(open(MSGFILE, O_RDONLY | O_CREAT, 0777));
    
        //根据msgfile生成一个key
        key_t key = ftok(MSGFILE, 1);
    
        //获取到消息队列
        int msgid = msgget(key, IPC_CREAT | 0777);
        if(msgid == -1)
        {
            perror("msgget");
            return -1;
        }
    
        struct msgbuf  msg;
        struct student stu;
    
        //从消息队列中取消息
        if(msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0) > 0)
        {
            //printf("%s\n", msg.mtext);
            //printf("%d\n", *((int *)msg.mtext));
            memcpy(&stu, msg.mtext, sizeof(stu));
            printf("%d %s\n", stu.age, stu.name);
        }
    
        
    
        return 0;
    }
    ```
    ### 4.共享存储
    ```
            ftok
            shmget  创建共享内存
            shmat   获取到共享内存的地址
            shmdt   释放共享内存的地址
            shmctl  销毁共享内存
    ```
    ### 5.信号量

    相关文章

      网友评论

          本文标题:复习

          本文链接:https://www.haomeiwen.com/subject/ckxpattx.html