美文网首页
系统编程-线程

系统编程-线程

作者: 帅碧 | 来源:发表于2016-12-05 19:41 被阅读0次
    • 作业
    • 用代码实现汽车发动以及停车,乘客上车,售票员等功能
    
    #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 handleDrive(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()
    {
        pid=fork();
        if(pid>0)//drive
        {
            signal(SIGINT,handleDrive);//注册信号
            signal(SIGUSR1,handleDrive);
            printf("司机等待售票员做好开车准备\n");
            while(1)
            {
                pause();
            }   
        }
        else if(pid==0)//conductor
        {
            signal(SIGINT,SIG_IGN);
            signal(SIGUSR2,handleConductor);
            sleep(1);
            //发送和一个开车信号,让其开车
            kill(getppid(),SIGUSR1);
            while(1)
            {
                pause();//有信号则返回,无信号就挂起
            }
        }
        else if(pid==-1)//创建进程失败
        {
            perror("fork");
            return -1;
        }
        return 0;
    }
    
    
    
    Paste_Image.png

    线程

    并发执行

    • 同时存在,同时运行.(并不是同时运行的,分给A10ms,运行完之后,则挂起,再给B10ms.由于时间很短,人为看不出来,以为是同时运行的)

    时间片

    创建线程

    • 编译时一定要加-pthread
    • 以下程序:测试两个线程是否同时运行
    • 是交替执行,不是并发
    
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    
    Paste_Image.png
    • 5s之后将线程结束,但是main函数继续执行
      //使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂断
    1. 一个进程创建线程后,创建的线程同属于该进程,不独立于进程,共享进程的所有资源.
    2. 线程是最小的执行单元,若一个进程没有创建线程,我们既可以把它看作是进程,也可以是相当于线程,若一个进程创建线程之后,我们可以将该线程称之为主线程,一个进程可以创建多个线程,线程之间资源共享
    
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        int i=0;//将这个线程,5s之后结束
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
            i++;
            if(i==5)
            {
                return NULL;
            }
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    
    Paste_Image.png
    • 使用exit之后,exit会将该线程所属的进程挂掉,当然线程也会挂断
    
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    
    void *thread_run(void *arg)
    {
        int i=0;//将这个线程,5s之后结束
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
            i++;
            if(i==5)
            {
                //使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂掉
                exit(1);
            }
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    Paste_Image.png
    • 资源共享
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.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()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    
    • 没有将iData拷贝一份,而是资源共享
    Paste_Image.png

    参数的传递

    1. 将地址传给他
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    #include<unistd.h>
    
    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);
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        int iArg=1999;
        ret=pthread_create(&thread,NULL,thread_run,&iArg);//将参数的地址传给他
        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;
    
    }
    
    
    Paste_Image.png
    
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    #include<unistd.h>
    
    void *thread_run(void *arg)
    {
        while(1)
        {
        
            printf("this is thread_run...arg=%d\n",(int)arg);
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        int iArg=1999;
        pthread_create(&thread,NULL,thread_run,(void *)iArg);//或者(void *)1888效果如上
        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;
    
    }
    
    
    Paste_Image.png
    1. 将结构体传给他
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    #include<unistd.h>
    typedef struct Student
    {
        int iId;
        char caName[32];
        float fScore;
    }Student;
    void *thread_run(void *arg)
    {
        while(1)
        {
            Student *pStu=(Student *)arg;
            printf("id:%d,name:%s,score:%.2f\n",pStu->iId,pStu->caName,pStu->fScore);
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        int iArg=1999;
        Student stu={1001,"zhangsan",89};
        ret=pthread_create(&thread,NULL,thread_run,&stu);
    //  ret=pthread_create(&thread,NULL,thread_run,(void *)stu);//这种方法不可以
        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;
    
    }
    
    
    Paste_Image.png

    pthread cancel(发送一个请求)

    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        //在线程函数中调用pthread_setcancelstate来设置
        //不同意结束线程请求,阻塞线程结束请求
        //直到线程允许接收线程结束请求
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
        if(0!=ret)
        {
            printf("errno:%d,error:%s\n",ret,strerror(ret));
            return -1;
        }
        sleep(3);
        //发送一个结束线程请求给指定线程,默认情况下,线程会同意该结束线程请求,还可以设置不同意
        pthread_cancel(thread);//3秒之后让线程挂掉
        while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
        {
            printf("this is main...\n");
            sleep(1);
        }
        return 0;
    }
    
    
    Paste_Image.png

    pthread_exit

    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        //在线程函数中调用pthread_setcancelstate来设置
        //不同意结束线程请求,阻塞线程结束请求
        //直到线程允许接收线程结束请求
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
        if(0!=ret)
        {
            printf("errno:%d,error:%s\n",ret,strerror(ret));
            return -1;
        }
        sleep(3);
        //若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束明若没有其他线程,则结束
        pthread_exit(NULL);
        while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
        {
            printf("this is main...\n");
            sleep(1);
        }
        return 0;
    }
    
    
    
    • 一直等待其他线程的结束,则退出.如果其他线程结束,则退出
    Paste_Image.png
    
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.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;//则执行一次,退出程序
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
        if(0!=ret)
        {
            printf("errno:%d,error:%s\n",ret,strerror(ret));
            return -1;
        }
        sleep(3);
        //若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束,若没有其他线程,则结束
        pthread_exit(NULL);
        while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
        {
            printf("this is main...\n");
            sleep(1);
        }
        return 0;
    }
    
    
    
    Paste_Image.png
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.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()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
        if(0!=ret)
        {
            printf("errno:%d,error:%s\n",ret,strerror(ret));
            return -1;
        }
        sleep(3);
        while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
        {
            printf("this is main...\n");
            sleep(1);
        }
        return 0;
    }
    
    
    Paste_Image.png

    pthread_join等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值

    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    
    Paste_Image.png
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    void *thread_run(void *arg)
    {
        while(1)
        {
            printf("this is thread_run...\n");
            sleep(1);
            break;
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    
    Paste_Image.png

    pthread_addNum

    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.h>
    int g_iData=0;
    void *thread_run(void *arg)
    {
        while(1)
        {
            ++g_iData;
            printf("thread :data=%d\n",g_iData);
        }
        return NULL;
    }
    
    int main()
    {
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
        if(0!=ret)
        {
            printf("errno:%d,error:%s\n",ret,strerror(ret));
            return -1;
        }
        while(1)
        {
            ++g_iData;
            printf("main :data=%d\n",g_iData);
        }
        return 0;
    
    }
    
    
    
    • g_iData=0;A线程++g_iData,如果线程A时间足够的话,则g_iData=1;B线程再执行,则变为2;
    • 若A时间片不够,虽然++了但++后的值还没有返回到g_iData里,所以B线程++后的值仍然为1
    • 如下,会出现中断的情况
    Paste_Image.png
    • 解决以上情况,则定义一个原子锁
    #include<pthread.h> //pthread_create()
    #include<stdio.h>
    #include<string.h>//strerror()
    #include<errno.h> //errno
    #include<stdlib.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);
            ++g_iData;
            printf("thread :data=%d\n",g_iData);
            pthread_mutex_unlock(&mutex);
        }
        return NULL;
    }
    
    int main()
    {
        
        //初始化互斥量,NULL表示使用默认属性初始化该互斥量
        pthread_mutex_init(&mutex,NULL);//使用他的默认属性进行初始化
        pthread_t thread;
        int ret=0;
        ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;
    
    }
    
    
    • 这样就不会出现中断的情况

    一个线程从文件读取数据,另一个线程打印出来

    • 先通过以前的代码,在文件里写入几个同学的信息
    
    #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_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;
    }
    
    
    Paste_Image.png

    信号量(sem_wait)

    //int sem_init();//pshared

    #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 print_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,接着往下执行,并且将该变量减1,如果等于0,则阻塞,直到该值大于0
                sem_wait(&read_sem);//此时read_sem=1
                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(&print_sem);//出错了,发送这个信号
                    break;
                }
                else if (-1 == ret)
                {
                    printf("read error:%s\n", strerror(errno));
                    pthread_mutex_unlock(&mutex);
                    sem_post(&print_sem);//出错了,发送这个信号
                    break;
                }
                pthread_mutex_unlock(&mutex);
                sem_post(&print_sem);//出错了,发送这个信号
            }
            close(fd);
        }   
    
        return NULL;
    }
    
    void *print_thread(void *arg)
    {
        Student *pStu = (Student *)arg;
        int i = 0;
        while (1)
        {
            //如果print_sem大于0,接着往下执行,并且将该变量减1,如果等于0,则阻塞,直到该值大于0
            sem_wait(&print_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);
            //将信号量的值加1
            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(&print_sem,0,0);//将print_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;
    }
    
    
    
    Paste_Image.png

    用代码模仿5个哲学家进餐问题

    1. 创建5根筷子(5个信号量创建一组信号量)
    2. 创建5科学家
    3. 获得筷子
    4. 放下筷子
    5. 继续思考
    int semop(int semid, struct sembuf *sops, unsigned nsops);
    
    

    参数

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

    相关文章

      网友评论

          本文标题:系统编程-线程

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