美文网首页
线程thread(day06)

线程thread(day06)

作者: 萌面大叔2 | 来源:发表于2016-12-12 05:54 被阅读0次

    作业1

    司机: 接收售票员关门信号-->开车 //SIGUSR1
    接收到站信号-->停车 //SIGINT
    发送开门信号给售票员-->等待关门信号 //pause() 挂起进程
    售票员:发送关门信号
    接收开门信号-->开门 //SIGUSR2

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>  //fork ()
    #include <stdlib.h>
    #include <sys/types.h> //kill()
    #include <signal.h>  //signal()
    
    pid_t pid = -1;
    
    //司机:到站停车  --> SIGINT  ctrl+c
    //      关门开车  --> SIGUSR1
    void handleDriver(int sig)
    {
        if (SIGINT == sig)
        {
            printf("到站了...\\n");
            sleep(1);
            printf("司机开始停车...\\n");
            sleep(1);
            int ret = 0;
            ret = kill(pid, SIGUSR2);  //发送信号给售票员让她开门
            if (-1 == ret)
            {
                perror("kill");
            }
        }
        else if (SIGUSR1 == sig)
        {
            printf("司机开始开车...\\n");
            sleep(1);
            printf("车正在跑...\\n");   
            sleep(1);
        }
    }
    //售票员:开门 -->SIGUSR2
    void handleConductor(int sig)
    {
        if (SIGUSR2 == sig)
        {
            printf("售票员开门...\\n");
            sleep(1);
            printf("乘客上车...\\n");
            sleep(1);
            printf("售票员关门...\\n");
            sleep(1);
            kill(getppid(), SIGUSR1);  //售票员发送信号给司机开车
        }
    }
    
    int main(void)
    {
        pid = fork();
        if (pid > 0)  //driver
        {
            signal(SIGINT, handleDriver);
            signal(SIGUSR1, handleDriver);
            printf("司机等待售票员做好开车准备...\\n");
            while (1)
            {
                pause();
            }   
        }
        else if (0 == pid)  //conductor
        {
            signal(SIGINT, SIG_IGN);
            signal(SIGUSR2, handleConductor);
            sleep(1);
            //发送一个开车信号让其开车
            kill(getppid(), SIGUSR1);
            while (1)
            {
                pause();    
            }   
        }
        else if (-1 == pid)
        {
            perror("fork");
            return -1;
        }
    
        return 0;
    }
    

    运行结果:


    1.PNG

    创建线程

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    void *thread_run(void *arg)
    {
        while (1)
        {
            printf("this is thread_run...\\n");
            sleep(1);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        while (1)
        {
            printf("this is main...\\n");
            sleep(1);
        }
    
        return 0;
    }
    

    运行结果:

    2.PNG

    pthread_arg.c

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    typedef struct Student
    {
        int iId;
        char caName[32];
        float fScore;
    }Student;
    
    void *thread_run(void *arg)
    {
        while (1)
        {
            //printf("this is thread_run...arg = %d\\n", *(int *)arg);
            //printf("this is thread_run...arg = %d\\n", (int)arg);
            Student *pStu = (Student *)arg;
            printf("id:%d, name:%s, score:%.2f\\n"
                   , pStu->iId, pStu->caName, pStu->fScore);
            sleep(1);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        int iArg = 1888;
        //ret = pthread_create(&thread, NULL, thread_run, &iArg);
        //ret = pthread_create(&thread, NULL, thread_run, (void *)iArg);
        //ret = pthread_create(&thread, NULL, thread_run, (void *)1888);
        Student stu = {1001, "zhangsan", 89};
        ret = pthread_create(&thread, NULL, thread_run, &stu);
        //ret = pthread_create(&thread, NULL, thread_run, (void *)stu);  //error
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        while (1)
        {
            printf("this is main...\\n");
            pause();
        }
    
        return 0;
    }
    
    

    运行结果:


    1.PNG

    pthread_cancel_exit.c

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    void *thread_run(void *arg)
    {
        //在线程函数中调用pthread_setcancelstate来设置
        //不同意结束线程请求,阻塞线程结束请求
        //直到线程允许接收线程结束请求
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        while (1)
        {
            printf("this is thread_run...\\n");
            sleep(1);
            //break;
            //结束所属线程
            //pthread_exit(NULL);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        sleep(3);
        //发送一个结束线程请求给指定的线程
        //默认情况下,线程会同意该结束线程请求
        //还可以设置不同意
        //pthread_cancel(thread);
        
        //若存在主线程中,如果含有其他线程存在,
        //则阻塞等待线程的结束
    
        //若没有其他线程,则结束程序
        pthread_exit(NULL);
        while (1)
        {
            printf("this is main...\\n");
            sleep(1);
        }
    
        return 0;
    }
    

    运算结果:


    1.PNG

    pthread_exit.c

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>  //sleep()
    #include <stdlib.h>  //exit()
    
    //一个进程创建线程后,创建的线程从属于该进程
    //不独立于进程,共享进程的所有资源
    
    //线程是最小的执行单元,
    //若一个进程没有创建线程,我们既可以把它看做是进程,也可以是相当于线程
    //若一个进程创建线程后,我们可以将该进程称之为主线程
    //一个进程可以创建多个线程,线程之间资源共享
    void *thread_run(void *arg)
    {
        int i = 0;
        while (1)
        {
            printf("this is thread_run...\\n");
            sleep(1);
            i++;
            if (5 == i)
            {
                //使用return 只能结束当前线程
                //return NULL;
    
                //会将该线程所属的进程挂掉,当然线程也会挂掉
                exit(1);
            }
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        while (1)
        {
            printf("this is main...\\n");
            sleep(1);
        }
    
        return 0;
    }
    

    运算结果:


    1.PNG

    pthread_join.c

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    void *thread_run(void *arg)
    {
        while (1)
        {
            printf("this is thread_run...\\n");
            sleep(1);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        //等待线程结束,若线程在运行,则阻塞等待
        //若线程结束,立即返回
        //第一个参数:要等待的线程
        //第二个参数:要来获得线程的返回值
        pthread_join(thread, NULL);
        while (1)
        {
            printf("this is main...\\n");
            sleep(1);
        }
    
        return 0;
    }
    

    运算结果:

    1.PNG

    pthread_mutex.c

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    pthread_mutex_t mutex;   //互斥量--锁
    
    int g_iData = 0;
    
    void *thread_run(void *arg)
    {
        while (1)
        {
            //使用pthread_mutex_lock和pthread_mutex_unlock
            //使它们之间的语句合成原子操作
    
            //若其他线程没有释放该互斥量
            //则本线程阻塞等待
            //pthread_mutex_lock(&mutex);
            //pthread_mutex_trylock(&mutex);
            ++g_iData;
            printf("thread:data = %d\\n", g_iData);
            pthread_mutex_unlock(&mutex);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        //初始化互斥量,NULL表示使用默认属性初始化该互斥量
        pthread_mutex_init(&mutex, NULL);
        
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        while (1)
        {
            pthread_mutex_lock(&mutex);
            ++g_iData;
            printf("main:data = %d\\n", g_iData);
            pthread_mutex_unlock(&mutex);
        }
    
        return 0;
    }
    
    

    运算结果:

    2.PNG

    pthread_share

    #include <pthread.h>  //pthread_create()
    
    #include <stdio.h>
    #include <string.h> //strerror()
    #include <errno.h>  //errno
    #include <unistd.h>
    
    int g_iData = 999;
    
    void *thread_run(void *arg)
    {
        //while (1)
        {
            printf("this is thread_run...iData = %d\\n", g_iData);
            g_iData++;
            //sleep(1);
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_t thread;
        int ret = 0;
        ret = pthread_create(&thread, NULL, thread_run, NULL);
        if (0 != ret)
        {
            printf("errno:%d, error:%s\\n", ret, strerror(ret));
            return -1;
        }
        sleep(2);
        //  while (1)
        {
            printf("this is main...iData = %d\\n", g_iData);
    //      sleep(1);
        }
    
        return 0;
    }
    

    运算结果:

    1.PNG

    read_stu

    #include <stdio.h>
    #include <unistd.h>  //write()  read()
    #include <errno.h>   //errno
    #include <string.h>  //strerror()
    /*open()*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <pthread.h> //pthread_create
    
    pthread_mutex_t mutex;
    
    #define NAME_LEN 32
    typedef struct Student
    {
        int iId;
        char caName[NAME_re LEN];
        char cSex;
        float fScore;
    
    }Student;
    
    int myOpen(const char *pathname)
    {
        int fd  = -1;
        if (NULL != pathname)
        {
            fd = open(pathname, O_RDONLY | O_CREAT
                      , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (-1 == fd)
            {
                printf("open error: %s\\n", strerror(errno));
            }
        }
        return fd;
    }
    
    int g_iSign = 0;
    
    void *read_thread(void *arg)
    {
        int fd = -1;
        fd = myOpen("stu.info");
        if (-1 != fd)
        {
            int ret = -1;
            Student *pStu = (Student *)arg;
            while (1)
            {
                if (0 == g_iSign)
                {
                    pthread_mutex_lock(&mutex);
                    memset(pStu, '\\0', sizeof(Student));
                    ret = read(fd, pStu, sizeof(Student));
                    if (0 == ret)
                    {
                        printf("reached the file end\\n");
                        pthread_mutex_unlock(&mutex);
                        g_iSign = 1;
                        break;
                    }
                    else if (-1 == ret)
                    {
                        printf("read error:%s\\n", strerror(errno));
                        pthread_mutex_unlock(&mutex);
                        g_iSign = 1;
                        break;
                    }
                    pthread_mutex_unlock(&mutex);
                    g_iSign = 1;
                }
            }
            close(fd);
        }   
    
        return NULL;
    }
    
    void *print_thread(void *arg)
    {
        Student *pStu = (Student *)arg;
        int i = 0;
        while (1)
        {
            if (1 == g_iSign)
            {
                pthread_mutex_lock(&mutex);
                if (0 == pStu->iId)
                {
                    pthread_mutex_unlock(&mutex);
                    break;
                }
            
                printf("id:%d, name:%s, sex:%c, score:%.1f\\n"
                       , pStu->iId, pStu->caName
                       , pStu->cSex, pStu->fScore);
            
                pthread_mutex_unlock(&mutex);
                g_iSign = 0;
            }
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_mutex_init(&mutex, NULL);
    
        Student stu;
        pthread_t pthr_read;
        pthread_t pthr_show;
    
        pthread_create(&pthr_read, NULL, read_thread, &stu);
        pthread_create(&pthr_show, NULL, print_thread, &stu);
    
        pthread_join(pthr_read, NULL);
        pthread_join(pthr_show, NULL);
    
        return 0;
    }
    

    运算结果:


    3.PNG

    write_stu.c

    #include <stdio.h>
    #include <unistd.h>  //write()
    #include <errno.h>   //errno
    #include <string.h>  //strerror()
    /*open()*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define NAME_LEN 32
    typedef struct Student
    {
        int iId;
        char caName[NAME_LEN];
        char cSex;
        float fScore;
    
    }Student;
    
    int myOpen(const char *pathname)
    {
        int fd  = -1;
        if (NULL != pathname)
        {
            fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC
                      , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (-1 == fd)
            {
                printf("open error: %s\\n", strerror(errno));
            }
        }
        return fd;
    }
    
    int main(void)
    {
        int fd = -1;
        fd = myOpen("stu.info");
        if (-1 != fd)
        {
            Student stu[6] = {{1001, "zhangsan", 'f', 99}
                              , {1002, "lisi", 'm', 79}
                              , {1003, "wangwu", 'f', 89}
                              , {1004, "zhaoliu", 'm', 69}
                              , {1005, "xiaoqi", 'm', 79}
                              , {1006, "laoba", 'f', 89}};
            int ret = -1;
            int i = 0;
            for (; i < 6; i++)
            {
                ret = write(fd, stu+i, sizeof(Student));
                if (-1 == ret)
                {
                    printf("write error: %s\\n", strerror(errno));
                }
                else
                {
                    printf("write %d bytes to file\\n", ret);
                }
            }
        }   
    
        return 0;
    }
    
    1.PNG

    sem_read_stu.c

    #include <stdio.h>
    #include <unistd.h>  //write()  read()
    #include <errno.h>   //errno
    #include <string.h>  //strerror()
    /*open()*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <pthread.h> //pthread_create
    #include <semaphore.h>  
    
    pthread_mutex_t mutex;
    
    sem_t read_sem;  //整形 
    sem_t show_sem;
    
    #define NAME_LEN 32
    typedef struct Student
    {
        int iId;
        char caName[NAME_LEN];
        char cSex;
        float fScore;
    
    }Student;
    
    int myOpen(const char *pathname)
    {
        int fd  = -1;
        if (NULL != pathname)
        {
            fd = open(pathname, O_RDONLY | O_CREAT
                      , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (-1 == fd)
            {
                printf("open error: %s\\n", strerror(errno));
            }
        }
        return fd;
    }
    
    void *read_thread(void *arg)
    {
        int fd = -1;
        fd = myOpen("stu.info");
        if (-1 != fd)
        {
            int ret = -1;
            Student *pStu = (Student *)arg;
            while (1)
            {
                //如果read_sem大于0,接着往下执行,并且将该变量减一
                //如果read_sem等于0,则阻塞,直到该值大于0
                sem_wait(&read_sem);
                
                pthread_mutex_lock(&mutex);
                
                memset(pStu, '\\0', sizeof(Student));
                ret = read(fd, pStu, sizeof(Student));
                if (0 == ret)
                {
                    printf("reached the file end\\n");
                    pthread_mutex_unlock(&mutex);
                    sem_post(&show_sem);
                    break;
                }
                else if (-1 == ret)
                {
                    printf("read error:%s\\n", strerror(errno));
                    pthread_mutex_unlock(&mutex);
                    sem_post(&show_sem);
                    break;
                }
                pthread_mutex_unlock(&mutex);
                //将信号量的值加一
                sem_post(&show_sem);
            }
        }
        close(fd);
    
        return NULL;
    }
    
    void *print_thread(void *arg)
    {
        Student *pStu = (Student *)arg;
        int i = 0;
        while (1)
        {
            {
                //如果show_sem大于0,接着往下执行,并且将该变量减一
                //如果show_sem等于0,则阻塞,直到该值大于0
                sem_wait(&show_sem);
                pthread_mutex_lock(&mutex);
                if (0 == pStu->iId)
                {
                    pthread_mutex_unlock(&mutex);
                    sem_post(&read_sem);
                    break;
                }
            
                printf("id:%d, name:%s, sex:%c, score:%.1f\\n"
                       , pStu->iId, pStu->caName
                       , pStu->cSex, pStu->fScore);
            
                pthread_mutex_unlock(&mutex);
                //将信号量的值加一
                sem_post(&read_sem);
            }
        }
    
        return NULL;
    }
    
    int main(void)
    {
        pthread_mutex_init(&mutex, NULL);
    
        //初始化信号量
        sem_init(&read_sem, 0, 1);  //将read_sem值置为1
        sem_init(&show_sem, 0, 0);  //将show_sem值置为0
    
        Student stu;
        pthread_t pthr_read;
        pthread_t pthr_show;
    
        pthread_create(&pthr_read, NULL, read_thread, &stu);
        pthread_create(&pthr_show, NULL, print_thread, &stu);
    
        pthread_join(pthr_read, NULL);
        pthread_join(pthr_show, NULL);
    
        return 0;
    }
    

    运算结果:


    1.PNG

    write_stu.c

    #include <stdio.h>
    #include <unistd.h>  //write()
    #include <errno.h>   //errno
    #include <string.h>  //strerror()
    /*open()*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #define NAME_LEN 32
    typedef struct Student
    {
        int iId;
        char caName[NAME_LEN];
        char cSex;
        float fScore;
    
    }Student;
    
    int myOpen(const char *pathname)
    {
        int fd  = -1;
        if (NULL != pathname)
        {
            fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC
                      , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (-1 == fd)
            {
                printf("open error: %s\\n", strerror(errno));
            }
        }
        return fd;
    }
    
    int main(void)
    {
        int fd = -1;
        fd = myOpen("stu.info");
        if (-1 != fd)
        {
            Student stu[6] = {{1001, "zhangsan", 'f', 99}
                              , {1002, "lisi", 'm', 79}
                              , {1003, "wangwu", 'f', 89}
                              , {1004, "zhaoliu", 'm', 69}
                              , {1005, "xiaoqi", 'm', 79}
                              , {1006, "laoba", 'f', 89}};
            int ret = -1;
            int i = 0;
            for (; i < 6; i++)
            {
                ret = write(fd, stu+i, sizeof(Student));
                if (-1 == ret)
                {
                    printf("write error: %s\\n", strerror(errno));
                }
                else
                {
                    printf("write %d bytes to file\\n", ret);
                }
            }
        }   
    
        return 0;
    }
    

    运算结果:


    1.PNG

    think-eat.c

    /*semget()*/
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    
    #include <string.h> //perror()
    #include <unistd.h> //fork()
    #include <stdio.h>  //printf()
    
    union semun 
    {
        int val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT,IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */                                                      
    };
    
    #if 0
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    
    参数
    semid:信号集的识别码,可通过semget获取。
    sops:指向存储信号操作结构的数组指针,信号操作结构的原型如下
    struct sembuf
    {
            unsigned short sem_num; /* semaphore number */
            short sem_op; /* semaphore operation */
            short sem_flg; /* operation flags */
    };
    这三个字段的意义分别为:
    sem_num:操作信号在信号集中的编号,第一个信号的编号是0。
    
    sem_op:
       1, 如果其值为正数,该值会加到现有的信号内含值中。
          通常用于释放所控资源的使用权;
       2, 如果sem_op的值为负数,而其绝对值又大于信号的现值,
          操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
          通常用于获取资源的使用权;
       3, 如果sem_op的值为0,如果没有设置IPC_NOWAIT,
          则调用该操作的进程或者线程将暂时睡眠,直到信号量的值为0;      否则,进程或者线程不会睡眠,函数返回错误EAGAIN。
    
    sem_flg:信号操作标志,可能的选择有两种
       1, IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,
          并立即返回,同时设定错误信息。
       2, SEM_UNDO //程序结束时(不论正常或不正常),
          保证信号值会被重设为semop()调用前的值。
          这样做的目的在于避免程序在异常情况下结束时
          未将锁定的资源解锁,造成该资源永远锁定。
    
    nsops:信号操作结构的数量,恒大于或等于1。
    #endif
    
    void getChopsticks(int iNum, int *semfd)
    {
        int iLeft = iNum;
        int iRight = (iNum + 1)%5;
    
        struct sembuf semope[2] = {{iLeft, -1, 0}
                                   , {iRight, -1, 0}};
        semop(*semfd, semope, 2);
    }
    
    void putChopsticks(int iNum, int *semfd)
    {
        int iLeft = iNum;
        int iRight = (iNum + 1)%5;
    
        struct sembuf semope[2] = {{iLeft, 1, 0}
                                   , {iRight, 1, 0}};
        semop(*semfd, semope, 2);
    }
    
    void thinkAndEat(int iNum, int *semfd)
    {
        while (1)
        {
            printf("%d say: I am thinking...\\n", iNum);
            /*拿筷子吃饭*/
            getChopsticks(iNum, semfd);
            sleep(1);
            printf("%d say: I am eatting...\\n", iNum);
            /*放下筷子*/
            putChopsticks(iNum, semfd);
            printf("%d say: I am put chopsticks...\\n", iNum);
            sleep(1);
        }
    }
    
    int main(void)
    {
        int semfd = -1;
        //获得信号量集的标识,若信号量集不存在则创建
        semfd = semget(0x1024, 5, IPC_CREAT | 0777);
        if (-1 == semfd)
        {
            perror("semget");
            return -1;
        }
    
        //对信号集中的信号量赋值
        union semun sem;
        sem.val = 1;
        int i = 0;
        for (; i < 5; i++)
        {
            if (-1 == semctl(semfd, i, SETVAL, sem))
            {
                perror("semctl");
                return -1;
            }
        }
    
        //创建五个哲学家进程
        int num = 0;  //表示第几个哲学家
        pid_t pid = -1;
        for (i = 0; i < 4; i++)
        {
            pid = fork();
            if (pid > 0)  //parent
            {
                num = 4;
            }
            else if (0 == pid) //child
            {
                num = i;
                break;
            }
            else if (-1 == pid) //error
            {
                return -1;
            }
        }
        thinkAndEat(num, &semfd);
    
        return 0;
    }
    

    运算结果:

    2.PNG

    相关文章

      网友评论

          本文标题:线程thread(day06)

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