精华内容
下载资源
问答
  • 在python同步编程部分,需要分析和思考多个线程之间同步互斥问题,因此pv操作和信号量作为基础和重中之重,特此回顾pv操作和信号量。PV操作由P操作原语和V操作原语组成(原语即不可在分割的操作),对信号量(大部分是...

    在python同步编程部分,需要分析和思考多个线程之间同步互斥问题,因此pv操作和信号量作为基础和重中之重,特此回顾pv操作和信号量。

    PV操作由P操作原语和V操作原语组成(原语即不可在分割的操作),对信号量(大部分是cpu等资源)进行操作,具体定义如下:

    P(S):

    ①将信号量S的值减1,即S=S-1;

    ②如果S>=0,则该进程继续执行;否则该进程置为等待状态。

    V(S):

    ①将信号量S的值加1,即S=S+1;

    ②该进程继续执行;如果该信号的等待队列中有等待进程就唤醒一等待进程。

    p操作就是对s(信号量)进行操作,p操作占用一个资源(s=s-1),空闲信号量减一,此时s>=0说明刚才资源足以满足线程需求,线程运行,否则挂起。

    v操作是线程完成之后释放资源,此时(s=s+1),此时空闲资源数量+1,若此时资源满足挂起队列线程需要,则新线程运行。

    关于PV操作的总结:

    1.在多线程编程中使用PV操作能忽略代码具体的实现细节,这样确保总体思路的正确性。

    2.分析PV操作时紧紧抓住同步和互斥;

    同步主要分析:谁在等待?等待什么?分析清楚了,同步就出来了;

    互斥主要分析:那些资源是共享的,共享资源需进一步思考有没有必要互斥,比如果盘问题中果盘是共享资源,但是果盘操作并不需要互斥;

    展开全文
  • 2016 2016年12月27日 PAGE # / 19 @江塚大吟 学与通信工程学院 操作系统课程设计报告 题目linux系统下实现PV 题目linux 系统下实现PV操作 班级 软件工程1401 姓名 学号 指导老师: PAGE PAGE # / 19 目录 实验题目 ...
  • 计算机科学与通信工程学院 操作系统课程设计报告 题目 linux 系统下实现 PV操作 班级 软件工程 1401 姓名 : 学号 3 指导老师 2016 年 12 月 27 日 1 / 19 目录 一 实验题目 3 二 实验目的和要求 3 三 环境配置 4 四 ...
  • LinuxPV操作与共享存储区通信

    千次阅读 2011-11-12 23:42:44
    在使用共享存储区通信时会遇到当多人同时运行客户端代码通过共享存储区与服务器代码做应答时,共享存储区内容还...然而在LinuxPV操作基本编程是在下面的代码中学到的,现贴出来(注释是自己百度后添加的,里面很多参

          在使用共享存储区通信时会遇到当多人同时运行客户端代码通过共享存储区与服务器代码做应答时,共享存储区内容还没有来得及显示,就被恶意篡改的情况(上篇文章中有源码)。本文将通过Linux下的信号量机制(pv操作)解决这个问题。

          PV操作的基本原理是在计算机操作系统课中学到的,这里不再详述。然而在Linux下PV操作基本编程是在下面的代码中学到的,现贴出来(注释是自己百度后添加的,里面很多参数的设置需要费一番功夫弄明白。):     

    //注意:在Linux下编程,中文注释有可能编译通不过。提示错误为:编码不对。(以下代码在加注释后便出现此问题,编译时去掉注释)
    #include <sys/types.h>
    #include <unistd.h>
    #include <signal.h>//signal的头文件。
    #include <stdio.h>
    #include <string.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #define MY_SHMKEY 10071500		// need to change
    #define MY_SEMKEY 10071500		// need to change
    void sigend(int);//清除操作
    int shmid, semid;
    int main(void)
    {
        int *shmptr, semval, local;
        struct sembuf semopbuf;  //sembuf为信号量的数据结构。设置semopbuf中的值,通过semop指定,可改变当前指定信号量数据结构中的值。
        if((shmid=shmget(MY_SHMKEY, sizeof(int), IPC_CREAT|IPC_EXCL|0666)) < 0)//IPC_CREAT如果不存在则创建,如果存在则打开。IPC_EXCL只有不存在的时候才创建,如果系统中一存在,则错误。二者同时使用保证此共享内存为新建的。0666为可读可写权限。
        {			/* shared memory exists, act as client */
            shmid=shmget(MY_SHMKEY, sizeof(int), 0666);//获取共享存储区的ID
            semid=semget(MY_SEMKEY, 2, 0666);//获取信号量集ID
            shmptr=(int *)shmat(shmid, 0, 0);
            printf("Act as producer. To end, input 0 when prompted.\n\n");
    	printf("Input a number:\n");
    	scanf("%d", &local);
            while( local )
    	{
    	    semopbuf.sem_num=0;//指定操作信号量集中的第一个信号量
    	    semopbuf.sem_op=-1;
    	    semopbuf.sem_flg=SEM_UNDO;
    	    semop(semid, &semopbuf, 1);	//操作一个信号量。(p(s1))
    	    *shmptr = local;
    	    semopbuf.sem_num=1;
    	    semopbuf.sem_op=1;
    	    semopbuf.sem_flg=SEM_UNDO;
    	    semop(semid, &semopbuf, 1);	/* V(S2) */
    	    printf("Input a number:\n");
    	    scanf("%d", &local);
            }
        }
        else		/* acts as server */
        {
            semid=semget(MY_SEMKEY, 2, IPC_CREAT|0666);//创建信号量集(信号量被创建的情况有两种:1.键值为IPC_PRIVATE 2.指定一个系统中不存在的信号量集key值。同时标志中指定IPC_CREAT),2为信号量个数,即当前信号量集中有两个信号量		
            shmptr=(int *)shmat(shmid, 0, 0);//共享存储区挂接到shmptr上
    	semval=1;
    	semctl(semid, 0, SETVAL, semval);//SETVAL:设置信号量中一个单独的信号量的值。
    	semval=0;
    	semctl(semid, 1, SETVAL,semval);	/* set S2=0 */
            signal(SIGINT, sigend);//设置某一信号的对应动作.ctrl+c引发SIGINT,Kill命令引发SIGTERM
            signal(SIGTERM, sigend);
            printf("ACT CONSUMER!!! To end, try Ctrl+C or use kill.\n\n");
            while(1)
            {
    	    semopbuf.sem_num=1;//指定信号量集中的第二个信号量
    	    semopbuf.sem_op=-1;//如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。 
    	    semopbuf.sem_flg=SEM_UNDO;//SEM_UNDO保证程序异常结束时信号量的值回复到调用semop前的值。
    	    semop(semid, &semopbuf, 1);	/* P(S2) *///第三个参数指定本次操作的信号操作数量,必>1。
                printf("Shared memory set to %d\n", *shmptr);
    	    semopbuf.sem_num=0;
    	    semopbuf.sem_op=1;
    	    semopbuf.sem_flg=SEM_UNDO;
    	    semop(semid, &semopbuf, 1);	/* V(S1) */
            }
        }
    }
    
    void sigend(int sig)
    {
        shmctl(shmid, IPC_RMID, 0);
        semctl(semid, IPC_RMID, 0);
        exit(0);
    }
       下面是我的代码,在上次代码的基础上给Serve和Client做PV操作。

       先建立一个信号量集(里面有两个信号量)。1号服务器使用(初始资源为0),2号客户端使用(初始资源为1)。先运行服务器程序,后运行客户端程序。交替对其做PV操作。(具体参加源程序)

       memserve.c(服务器程序,按Ctrl+C结束):  

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>//信号量头文件
    #define SHM_Key 3001 //共享存储区Key
    #define SEM_Key 4001 //信号量Key
    void sigend(int);
    union   semun//此结构来自百度semctl.
    {
     int   val;// value for SETVAL 
     };
    int shmid,semid,*shmptr,val;//shmid放共享内存的ID,semid放信号量的ID
    int main(void)
    {
        struct sembuf semaphore;//定义一个信号量
        union semun semopts;//联合类型,在semctl中跟SETVAL配合使用,为信号量付初值
        if((shmid=shmget(SHM_Key, sizeof(int), IPC_CREAT|IPC_EXCL|0666)) < 0)//IPC_EXCL保证此信号量被创建后不能在被第二次IPC_CREAT
            printf("shmget error"), exit(1);
        if((shmptr=(int *)shmat(shmid, 0, 0)) == (int *)-1)//
            printf("shmat error"),exit(1);
        if((semid=semget(SEM_Key,2,IPC_CREAT|0666))<0)//创建信号量集(2个)
            printf("semget error"),exit(1);
        semopts.val=0;
        semctl(semid,0,SETVAL,semopts);//第一个信号量资源为0
        semopts.val=1;
        semctl(semid,1,SETVAL,semopts);//第二个信号量资源数为1
        signal(SIGINT, sigend);//设置某一信号的对应动作.ctrl+c引发SIGINT,Kill命令引发SIGTERM
        signal(SIGTERM, sigend);
        printf("Serve start: \n");
        while(1)		
        {    
           semaphore.sem_num=0;
           semaphore.sem_op=-1;
           semaphore.sem_flg=SEM_UNDO;//异常退出则撤销之前操作
           semop(semid,&semaphore,1);//(p(s1))因其初始资源0,阻塞。
           printf("Share Meomory's current value is %d\n",*shmptr);
           semaphore.sem_num=1;
           semaphore.sem_op=1;
           semaphore.sem_flg=SEM_UNDO;  
           semop(semid,&semaphore,1);//v(s2)    
        }
    }
    void sigend(int sig)
    {
        shmctl(shmid, IPC_RMID, 0);
        semctl(semid, IPC_RMID, 0);
        exit(0);
    }
       memclient.c(客户端程序):

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>//信号量头文件
    #define SHM_Key 3001 //共享存储区Key
    #define SEM_Key 4001 //信号量Key
    int main(void)
    {
        int shmid,*shmptr,semid;
        struct sembuf semaphore;
        shmid=shmget(SHM_Key, sizeof(int), 0666);
        if((shmptr=(int *)shmat(shmid, 0, 0)) == (int *)-1) //第二个参数指定引入位置,0表示由内核决定引入位置
            printf("shmat error"), exit(1);
        semid=semget(SEM_Key,2,0666);
        printf("Client start:\nInput a value :\n");
        while(1)
        {
          semaphore.sem_num=1;
          semaphore.sem_op=-1;
          semaphore.sem_flg=SEM_UNDO;
          semop(semid,&semaphore,1);//p(s2)
          scanf("%d",shmptr);
          semaphore.sem_num=0;
          semaphore.sem_op=1;
          semaphore.sem_flg=SEM_UNDO;
          semop(semid,&semaphore,1);//v(s1)
        }
       
    }
    运行结果如下:



    展开全文
  • 系统PV操作代码

    千次阅读 2010-07-04 17:22:00
    //一个可以边欣赏边熟悉操作系统PV操作代码 //如果不想浪费时间,仅看代码便能理解 //这是一个用于Unit/Linux代码,不适合用于XP,如果有需要,可以进行修改 view plaincopy to clipboard...

    //一个可以边欣赏边熟悉操作系统PV操作的代码
    //如果不想浪费时间,仅看代码便能理解
    //这是一个用于Unit/Linux的代码,不适合用于XP,如果有需要,可以进行修改

    view plaincopy to clipboardprint?
    #include <stdio.h>  
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <string.h>  
    #include <pthread.h>  
    #include <semaphore.h>  
     
    sem_t bin_sem;  
    void *thread_function1(void *arg)  
    {  
     printf("thread_function1--------------sem_wait/n");  
     sem_wait(&bin_sem);  
     printf("sem_wait/n");  
     while (1)  
     {  
     }  
    }  
     
    void *thread_function2(void *arg)  
    {  
     printf("thread_function2--------------sem_post/n");  
     sem_post(&bin_sem);  
     printf("sem_post/n");  
     while (1)  
     {  
     }  
    }  
     
    int main()  
    {  
     int res;  
     pthread_t a_thread;  
     void *thread_result;  
       
     res = sem_init(&bin_sem, 0, 0);  
     if (res != 0)  
     {  
      perror("Semaphore initialization failed");  
     }  
     printf("sem_init/n");  
     res = pthread_create(&a_thread, NULL, thread_function1, NULL);  
     if (res != 0)  
     {  
      perror("Thread creation failure");  
     }  
     printf("thread_function1/n");  
     sleep (5);  
     printf("sleep/n");  
     res = pthread_create(&a_thread, NULL, thread_function2, NULL);  
     if (res != 0)  
     {  
      perror("Thread creation failure");  
     }  
     while (1)  
     {  
     }  

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <semaphore.h>

    sem_t bin_sem;
    void *thread_function1(void *arg)
    {
     printf("thread_function1--------------sem_wait/n");
     sem_wait(&bin_sem);
     printf("sem_wait/n");
     while (1)
     {
     }
    }

    void *thread_function2(void *arg)
    {
     printf("thread_function2--------------sem_post/n");
     sem_post(&bin_sem);
     printf("sem_post/n");
     while (1)
     {
     }
    }

    int main()
    {
     int res;
     pthread_t a_thread;
     void *thread_result;
     
     res = sem_init(&bin_sem, 0, 0);
     if (res != 0)
     {
      perror("Semaphore initialization failed");
     }
     printf("sem_init/n");
     res = pthread_create(&a_thread, NULL, thread_function1, NULL);
     if (res != 0)
     {
      perror("Thread creation failure");
     }
     printf("thread_function1/n");
     sleep (5);
     printf("sleep/n");
     res = pthread_create(&a_thread, NULL, thread_function2, NULL);
     if (res != 0)
     {
      perror("Thread creation failure");
     }
     while (1)
     {
     }
    }
     

    //程序运行结果
    view plaincopy to clipboardprint?
    sem_init  
    thread_function1  
    thread_function1--------------sem_wait  
    sleep  
    thread_function2--------------sem_post  
    sem_wait  
    sem_post 
    sem_init
    thread_function1
    thread_function1--------------sem_wait
    sleep
    thread_function2--------------sem_post
    sem_wait
    sem_post

    //我看了不想看的讲解:

    //sem_wait  sem_post(2010-06-07 22:37:39)
    //信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
    //
    //extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  
    //
    //sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  
    //
    //函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  
    //
    //函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  
    //
    //函数sem_destroy(sem_t *sem)用来释放信号量sem。 
    //
    //信号量用sem_init函数创建的,下面是它的说明:
    //#include<semaphore.h>
    //int sem_init (sem_t *sem, int pshared, unsigned int value);
    //
    //这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。 (这个参数受版本影响), pshared传递一个非零将会使函数调用失败。
    //
    //这两个函数控制着信号量的值,它们的定义如下所示:
    //
    //#include <semaphore.h>
    //int sem_wait(sem_t * sem);
    //int sem_post(sem_t * sem);
    //
    //这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。
    //sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。
    //sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
    //信号量这种“只用一个函数就能原子化地测试和设置”的能力下正是它的价值所在。还有另外一个信号量函数sem_trywait,它是sem_wait的非阻塞搭档。
    //
    //最后一个信号量函数是sem_destroy。这个函数的作用是在我们用完信号量对它进行清理。下面的定义:
    //#include<semaphore.h>
    //int sem_destroy (sem_t *sem);
    //这个函数也使用一个信号量指针做参数,归还自己战胜的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。
    //与其它的函数一样,这些函数在成功时都返回“0”。
    //

    展开全文
  • Linux学习之PV操作及信号量

    千次阅读 2018-12-01 14:44:48
    文章目录学习Linux信号量及P, V操作 实例代码一. 利用信号量实现进程互斥实例二. 利用信号量实现进程同步三. 生产者,消费者同步问题1. 问题分析 :2. 同步算法 :3. 主程序实现算法四. 一家四口吃水果的同步问题 学习...

    学习Linux信号量及P, V操作 实例代码


    一. 利用信号量实现进程互斥实例

    设有父子两个进程共享一个临界资源, 每个进程循环进入该临界资源3次,父进程每次进入临界区后显示prnt in, 出临界区则显示prnt out; 子进程每次进入临界区后显示chld in, 出临界区则显示chld out. 观察运行结果, 要求进程互斥, 应该是一个进程进来后另一个才能进入

            设置互斥信号量mutex, 其内部标识为mutexid, 初值为1, 程序中使用睡眠延迟1秒来模拟进入临界区前和进入后所执行的程序

    程序实例代码:

    
    /*
     * @Author: D-lyw 
     * @Date: 2018-11-07 14:37:45 
     * @Last Modified by: D-lyw
     * @Last Modified time: 2018-11-10 20:59:36
     * @Descripe 利用信号量实现进程互斥的实例
     */
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/sem.h>
    
    union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };
    
    //定义信号量标识
    int mutexid;        
    
    int main(int argc, char const *argv[])
    {
        int chld, i, j;
    
        // 定义数据结构
        struct sembuf P, V;
        union semun arg;
    
        // 创建只含g一二互斥信号量u元素的信号量集
        mutexid = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
        // 为g信号量赋初值
        arg.val = 1;
        if(semctl(mutexid, 0, SETVAL, arg) == -1)
            perror("semctl setval error\n");
        
        // 定义P, V 操作
        P.sem_num = 0;
        P.sem_op = -1;
        P.sem_flg = SEM_UNDO;
        V.sem_num = 0;
        V.sem_op = 1;
        V.sem_flg = SEM_UNDO;
    
        while((chld = fork()) == -1);       // 创建子进程
        if(chld > 0){                       // 父进程返回
            i = 1;
            while(i <= 3){
                sleep(1);
                semop(mutexid, &P, 1);      // 进入临界区前执行P(mutex)
                printf("prnt in \n");
                sleep(1);
                printf("prnt out\n");
                semop(mutexid, &V, 1);      // 出临界区执行V(mutex)
                i++;
            }
            wait(0);                        // 等待子进程g终止
            semctl(mutexid, IPC_RMID, 0);   // 撤销信号量
            exit(0);
        }else{                              // 子进程返回
            j = 1;
            while(j <= 3){
                sleep(1);
                semop(mutexid, &P, 1);      // 进入临界区前执行P(mutex)
                printf("chld in\n");
                sleep(1);
                printf("chld out\n");
                semop(mutexid, &V, 1);      // 出临界区执行V(mutex)
                j++;
            }
            exit(0);
        }
        
        return 0;
    }
    
    

    程序运行结果:

    chld in
    chld out
    Print in 
    Prnt out
    chld in
    chld out
    Print in 
    Prnt out
    chld in
    chld out
    Print in 
    Prnt out
    

    分析:
            可见, 父子进程进入临街区是有序的, 没有发生穿插进入的情况, 即每次只能有一个进程进入临界区, 这正是因为使用信号量作为互斥信号的缘故. 若不使用信号量进行,则父子进程对临界区的进入就会出现穿插的,非互斥进入的情况.



    二. 利用信号量实现进程同步

    由父进程创建一个子进程, 父子进程共享一个存储区, 子进程向共享存储区中以覆盖方式写信息, 父进程从该共享存储区中读信息并显示信息. 父子进程轮流读写, 即子进程写一个信息到共享内存中, 父进程从中读取该信息输出; 然后子进程在第二个信息, 父进程再读出第二个信息输出, 当信息为end是读写进程结束

    单缓冲区同步问题

    • 同步分析
      这是一个单缓冲区同步问题, 读写缓冲区的两个进程之间只需要同步不需要互斥;
    • 同步算法
      子进程执行条件为单缓冲区为空, 设信号量为emptyid, 初值为1;
      父进程执行条件为单缓冲区有数, 设信号量为fullid, 初值为0;
      上述信号量可以为父进程定义, 申请, 初始化, 然后由父子进程共享使用, 子进程结束后由父进程撤销
    • 共享内存设计
      父子进程共享一个内存区, 可以由父进申请, 附接, 然后由父子进程共享使用, 子进程结束后共享内存由父进程撤销

    程序代码实例

    /*
     * @Author: D-lyw 
     * @Date: 2018-11-10 20:50:01 
     * @Last Modified by: D-lyw
     * @Last Modified time: 2018-11-10 20:54:33
     * @descripe 利用信号量实现进程同步 
     */
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/sem.h>
    #include <sys/shm.h>
    
    #define BUFSIZ 1024
    
    union semun{
        int val; 
        struct semid_ds *buf;
        unsigned short *array;
    };
    
    // 定义信号量内部标识
    int emptyid;
    int fullid;
    
    int main(){
        int chld;
    
        // 定义信号量数据结构
        struct sembuf P, V;
        union semun arg;
    
        // 定义共享内存
        int shmid;
        char *viraddr;
        char buffer[BUFSIZ];
    
        // 创建信号量并初始化
        emptyid = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
        fullid = semget(IPC_PRIVATE, 1, IPC_CREAT);
        arg.val = 1;
        if(semctl(emptyid, 0, SETVAL, arg) == -1)
            perror("semctl setval error");
        arg.val = 0;
        if(semctl(fullid, 0, SETVAL, arg) == -1)
            perror("semctl setval error");
        
        // 定义P, V 操作
        P.sem_num = 0;
        P.sem_op = -1;
        P.sem_flg = SEM_UNDO;
        V.sem_num = 0;
        V.sem_op = 1;
        V.sem_flg = SEM_UNDO;
    
        // agni创建并附接共享内存
        shmid =  shmget(IPC_PRIVATE, BUFSIZ, 0666|IPC_CREAT);
        viraddr = (char *)shmat(shmid, 0, 0);
    
        while ((chld = fork()) == -1);
        if(chld > 0){
            while(1){
                semop(fullid, &P, 1);                       // 对fullidx执行P 操作
                printf("Your message is: \n %s", viraddr);
                semop(emptyid, &V, 1);                      // 对emptyid执行V操作
                if(strncmp(viraddr, "end", 3) == 0)
                    break;
            }
            wait(0);  
            shmdt(viraddr);
            shmctl(shmid, IPC_RMID, 0);
            semctl(emptyid, IPC_RMID, 0);
            semctl(fullid, IPC_RMID, 0);
            printf("Parent exit!\n");
            exit(0);
        }else{
            while(1){
                semop(emptyid, &P, 1);                      // 对temptyid执行P操作
                puts("Enter your text:");
                fgets(buffer, BUFSIZ, stdin);
                strcpy(viraddr, buffer);
                semop(fullid, &V, 1);                       // 对fullidin执行V操作
                if(strncmp(viraddr, "end", 3) == 0){
                    sleep(1);                               // 睡眠1秒,等待父进程将"end"取走
                    break;
                }
            }
            printf("child exit!\n");
            exit(0);
        }
        return 0;
    }
    
    

    由运行结果可以看出, 子进程写到单缓冲区的信息, 父进程都取出并输出了
    注意: 在程序中,子进程在结束前的睡眠1秒是必要的,否则运行会出现不稳定规定情况,即有时正常退出,有时en不正常退出.究其原因,是父进程还没来得及取出end,子进程就已经发出结束信号而影响父进程的执行.



    三. 生产者,消费者同步问题

    设父进程创建1个子进程作为生产者,创建2个子进程作为消费者.这3个子进程使用一个共享内存, 该共享内存定义为具有5个变量的数组, 每个变量表示一个缓冲区, 缓冲区号为0-4. 生产者进程依次往缓冲区中写10个数据1-10, 俩个读进程依次从缓冲区0-4中轮流取出这10个数据.使用信号量实现进程读写缓冲区的同步和互斥,如图所示:

    生产者消费者同步问题

    1. 问题分析 :

    • 需要创建3个子进程 生产者, 消费者A, 消费者B;
    • 需要使用3个信号量empty, full , mutex, 分别表示缓冲区是否为空, 是否有数和互斥信号量, 其初值为5, 0, 1;
    • 需要2个共享内存 array, 和get , 分别表示多缓冲区数组array[0]~[4]和消费者缓冲区号的计数get, get计数由两个消费者进程共享, 由于只有一个生产者, 所以写缓冲区号计数变量set不需要使用共享内存.

    2. 同步算法 :

    生产者进程 消费者进程
    P(empty); P(full)
    P(mutex); P(mutex)
    将数据送到缓冲区 从缓冲区读取数据
    V(mutex); V(mutex)
    V(full); V(empty)

    由于父子进程可以共享资源, 所以3个信号量以及2个共享的内存可以在父进程中进行申请, 并完成初始化再创建子进程,在各子进程中直接使用.

    3. 主程序实现算法

    
    创建共享存储区array, get;
    附接共享存储区到进程空间;
    共享存储区赋初值;
    创建信号量empty并初始化;
    创建信号量full并初始化;
    创建信号量mutex并初始化;
    创建生产者子进程;
    
    如果生产者返回,:
    for(i = 0; i < 10; i++){
        P(empty);
        P(mutex);
        写数据到共享存储区;
        缓冲区计数set++;
        V(mutex);
        V(full);
        exit(0);
    }
    
    
    
    如果父进程返回:
    创建消费者A子进程;
        如果消费者A进程返回:
        for(i = 0; i < 10; i++){
            P(full);
            P(mutex);
            从共享存储区中取数据;
            缓冲区计数(*get)++;
            V(mutex);
            V(empty);
            exit(0);
        }
        如果父进程返回:
            创建消费者B子进程"
            如果消费者B进程返回:
                for(i = 0; i < 10; i++){
                    P(full);
                    P(mutex);
                    从共享存储区中取数据;
                    缓冲区计数(*get)++;
                    V(mutex);
                    V(empty);
                    exit(0);
                }
            如果父进程返回:
                wait(0);
                wait(0);
                wait(0);
                断开2个共享存储区;
                撤销2个共享存储区;
                撤销3个信号量;
                exit(0);
    
    

    完整实现代码:

    /*
     * @Author: D-lyw 
     * @Date: 2018-11-10 21:01:36 
     * @Last Modified by: D-lyw
     * @Last Modified time: 2018-11-11 10:20:59
     * @Description 生产者,消费者同步问题
     */
       
    #include <sys/types.h>
    #include <sys/sem.h>
    #include <sys/shm.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <errno.h>
    #include <time.h>
    #include <stdlib.h>
    
    union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };
    
    #define MAXSHM 5                // 定义n缓冲区数组的下标变量个数
    
    // 定义3个n信号量的内部标识
    int fullid;
    int emptyid;
    int mutexid;
    
    int main(int argc, char const *argv[])
    {
        // 定义信号量数据结构
        struct sembuf P, V;
        union semun arg;
    
        // 定义2个共享内存的ID
        int arrayid;
        int getid;
    
        // 定义共享内存虚拟地址
        int *array;
        int *get;
    
        // 创建共享内存虚拟地址
        arrayid = shmget(IPC_PRIVATE, sizeof(int )*MAXSHM, IPC_CREAT|0666);
        getid = shmget(IPC_PRIVATE, sizeof(int ), IPC_CREAT|0666);
    
        // 初始化共享内存
        array = (int *) shmat(arrayid, 0, 0);
        get = (int *) shmat(getid, 0, 0);
        *get = 0;
    
        // 创建信号量
        fullid = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
        emptyid = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
        mutexid = semget (IPC_PRIVATE, 1, IPC_CREAT|0666);
    
        // 初始化信号量
        arg.val = 0;                        // 初始时缓冲区无数据
        if(semctl(fullid, 0, SETVAL, arg) == -1) 
            perror("Semctl setval error");
        arg.val = MAXSHM;                   // i初始时缓冲区有5个空闲的数组元素
        if(semctl(emptyid, 0, SETVAL, arg) == -1)
            perror("semctl setval error");
        arg.val = 1;                        // 初始时i互斥信号为1, 允许一个进程进入
        if(semctl(mutexid, 0, SETVAL, arg) == -1)
            perror("setctl setval error");
        
        // 初始化P, V操作
        P.sem_num = 0;
        P.sem_op = -1;
        P.sem_flg = SEM_UNDO;
        V.sem_num = 0;
        V.sem_op = 1;
        V.sem_flg = SEM_UNDO;
    
        // 生产者进程
        if(fork() == 0){
            int i = 0; 
            int set = 0;
            while(i < 10){
                semop(emptyid, &P, 1);          // 对emptyid执行P操作
                semop(mutexid, &P, 1);          // 对muteid执行P操作
                array[set%MAXSHM] = i + 1;
                printf("Producer put number %d to NO. %d \n", array[set%MAXSHM], set%MAXSHM);
                set++;                          // 写计数加1
                semop(mutexid, &V, 1);          // 对mutexid执行V操作
                semop(fullid, &V, 1);           // 对fullidn执行V操作
                i++;
            }   
            sleep(3);
            printf("Producer is over!\n");
            exit(0);
        }else{
            // 消费者A进程
            if(fork() == 0){
                while(1){
                    if(*get == 10)
                        break;
                    semop(fullid, &P, 1);           // 对fullid执行P操作
                    semop(mutexid, &P, 1);           // 对mutexid执行P操作
                    printf("The ComsumerA get number from No. %d\n", (*get)%MAXSHM);
                    (*get)++;                       // 读计数加1
                    semop(mutexid, &V, 1);          // 对mutexid执行V操作
                    semop(emptyid, &V, 1);          // 对emptyid执行V操作
                    sleep(1);
                }
                printf("ConsumerA is over\n");
                exit(0);
            }
            else{
                if(fork() == 0){
                    while(1){
                        if(*get  == 10)
                            break;
                        semop(fullid, &P, 1);       // 对fullid执行P操作
                        semop(mutexid, &P, 1);      // 对mutexid执行P操作
                        printf("The comsumerB get number from No. %d \n", (*get)%MAXSHM);
                        (*get)++;
                        semop(mutexid, &V, 1);
                        semop(emptyid, &V, 1);
                        sleep(1);
                        printf("ConsumerB is over\n");
                        exit(0);
                    }
                }
            }
        }
    
        // 父进程返回后回收3个子进程
        wait(0);
        wait(0);
        wait(0);
    
        // 断开并撤销2个共享内存
        shmdt(array);
        shmctl(arrayid, IPC_RMID, 0);
        shmdt(get);
        shmctl(getid, IPC_RMID, 0);
    
        // 撤销3个信号量集
        semctl(emptyid, IPC_RMID, 0);
        semctl(fullid, IPC_RMID, 0);
        semctl(mutexid, IPC_RMID, 0);
    
        exit(0);
        
        return 0;
    }
    
    


    四. 一家四口吃水果的同步问题

    用四个线程来处理每个人对应的动作, 加上信号量来实现同步和互斥

    /*
     * @Author: D-lyw 
     * @Date: 2018-11-13 22:08:35 
     * @Last Modified by: D-lyw
     * @Last Modified time: 2018-11-14 01:15:01
     * @Descripe 
     *          桌子有一个盘子, 每次只能放入一个水果.
     *          爸爸专向盘子中放入苹果, 妈妈专向盘子中放橘子, 一个儿子专等吃盘子中的橘子, 一个女儿专吃盘子中的苹果
     *          试用PV操作实现四个人的同步
     * @Analysis
     *          爸爸,妈妈要互斥使用盘子,所以二者是互斥关系;
     *          爸爸放苹果, 女儿吃, 所以二者是同步关系;
     *          妈妈放的橘子, 儿子吃, 所以二者也是同步关系.
     *      定义三个信号量: SA, SO, mutex.
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/sem.h>
    #include <sys/shm.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <pthread.h>
    
    union semun{
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };
    
    // 定义SA, SO, mutex三个信号量的内部标识
    int SA;
    int SO;
    int mutex;
    
    // 创建共享区标识
    int plantid;
    char *plant;
    
    // 定义四个线程的线程ID
    pthread_t pM;
    pthread_t pF;
    pthread_t pS;
    pthread_t pD;
    
    // 定义数据结构
    struct sembuf P, V;
    union semun arg;
        
    void *mother(void *arg);
    void *father(void *arg);
    void *son(void *arg);
    void *daughter(void *arg);
    
    int main(int argc, char const *argv[])
    {
        plantid = shmget(IPC_PRIVATE, sizeof(char )*10, IPC_CREAT|0666);
        plant = (char *) shmat(plantid, 0, 0);
    
        // 创建信号量
        SA = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
        SO = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
        mutex = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
    
        // 为信号量赋初值
        arg.val = 0;
        if(semctl(SA, 0, SETVAL, arg) == -1){
            perror("semctl error");
        }
        if(semctl(SO, 0, SETVAL, arg) == -1){
            perror("semctl error");
        }
        arg.val = 1;
        if(semctl(mutex, 0, SETVAL, arg) == -1){
            perror("semctl error");
        }
    
        // 定义P, V操作
        P.sem_num = 0;              // 表示操作的是信号量集的第几个信号量
        P.sem_op = -1;
        P.sem_flg = SEM_UNDO;
        V.sem_num = 0;
        V.sem_op = 1;
        V.sem_flg = SEM_UNDO;
    
        pthread_create(&pM, NULL, mother, NULL);
        pthread_create(&pF, NULL, father, NULL);
        pthread_create(&pD, NULL, daughter, NULL);
        pthread_create(&pS, NULL, son, NULL);
    
        sleep(2);
        return 0;
    }
    
    void *mother(void *arg){
        int i = 3;
        while(i--){
            semop(mutex, &P, 1);
            // printf("妈妈向盘子放入一个 --橘子--\n");
            plant = "橘子";
            semop(SO, &V, 1);
        }
        return NULL;
    }
    
    void *father(void *arg){
        int i = 3; 
        while(i--){
            semop(mutex, &P, 1);
            // printf("爸爸向盘子放入一个 --苹果--\n");
            plant = "苹果";
            semop(SA, &V, 1);
        }
        return NULL;
    }
    
    void *son(void *arg){   
        int i = 3;
        while(i--){
            semop(SO, &P, 1);          // 对muteid执行P操作
            // printf("儿子从盘子中拿了一个 **橘子**\n");
            printf("儿子拿到: %s\n", plant);
            printf("--------------------------\n");
            semop(mutex, &V, 1);
        }
        return NULL;
    }
    
    void *daughter(void *arg){
        int i = 3;
        while(i--){
            semop(SA, &P, 1);
            // printf("女儿从盘子中拿了一个 **苹果**\n");
            printf("女儿拿到: %s\n", plant);
            printf("--------------------------\n");
            semop(mutex, &V, 1);
        }
        return NULL;
    }
    
    
    
    展开全文
  • 运行的效果就是:当左边的进程检测到EOF,释放资源V操作之后,右边的进程会迅速的执行对应的printf的操作! 所有代码文件结构如下: sem_a.c(左边进程的代码,编译方式:gcc sem_a.c sempv.c -o sem_a) #...
  • 简单基础的Linux高级编程相关代码,相关的实验代码,进程、线程,信号量,pv操作
  • 2.3构建工具链2.3.1进入LFS包编译目录代码:cd $LFS/sources从现在开始一直到构建工具链结束,重新启动恢复工作状态的步骤如下:1.重启进入 Ubuntu 系统,开启 bash2.加载分区export LFS=/mnt/lfssudo mkdir -pv $...
  • 1. linux下的中断实验不需要像裸机实验一样要自己写取消屏蔽,清除中断标志位的操作,系统会自动帮你完成; 2.中断号的申请我使用的是gpio_to_irq()这个宏,它会帮我们自动分配中断号,返回值为中断号; 3. 在每个...
  • 要求: (1)多个读者可以同时进行读;(2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行);(3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时...若不考虑互斥情况的代码为:Read(){ReadQ.push();...
  • Linux下完整C语言实现生产者消费者问题的代码。其中涉及信号量、多线程、GCC编译、PV操作等基础知识。Linux下通过gcc - o yy xxx.c -pthread,再通过./yy即可运行。
  • linux操作系统下c语言编程入门--消息...POSIX无名信号量 如果你学习过操作系统,那么肯定熟悉PV操作了.PV操作是原子操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在CPU上面执行.在系统当中,
  • 主要代码 net /drivers/net/wireless   主要操作是通过socket
  • 2,写一个服务器程序接收客户端命令,根据命令操作不同的设备 3,实现一个客户端程序,向服务器发送命令,控制设备 /* home_work_client.c 使用select多路复用实现TCP双向通信服务器端代码 实现一个客户端程序,向...
  • 在开始代码讲解之前,先看s5pv210的启动流程,因为uboot的初始化代码就是建立在芯片启动流程基础上的。三星系列芯片针对的都是手机、平板电脑等运行操作系统的设备,使用的是ARM-Cortex A系列架构,而不同于如STM32...
  • Linux-基础入门-学习笔记(3):uboot常用命令与环境变量一文中,已经对uboot的基本认识有了一个简单的介绍,也知道了uboot是引到操作系统启动和部署整个计算机系统的最重要的一部分,下面对uboot的配置和编译过程...
  • 前言:Linux下的进程通信(IPC) Linux下的进程通信(IPC) POSIX无名信号量 System V信号量 System V消息队列 System V共享内存 1、POSIX无名信号量如果你学习过操作系统,那么肯定熟悉PV操作了.PV操作是原子 操作....
  • [Linux]锁机制

    2017-10-06 19:35:19
    本文,记录Linux-pthread-lock-mechanism(锁机制)。 ...Linux各种锁的实现原理Linux底层锁的实现代码 操作系统课程里面,锁机制,两个操作称为:PV操作 什么是PV操作,链接 P是加锁V是
  • Linux信号量

    千次阅读 2012-03-18 09:44:02
    POSIX无名信号量 如果你学习过操作系统,那么肯定熟悉PV操作了.PV操作是原子  操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在CPU上面  执行.在系统当中,有时候为了顺利的使用和保护共享...
  • ARM开发板:S5PV210 驱动步骤: 1.定义一个cdev设备结构体变量 2.给cdev申请设备号 3.定义一个文件操作集 4.设备初始化 5.注册设备进内核 6.申请GPIO口 ...在内核代码 \arch\arm\mach-s5pv210\i
  • Linux下的信号量

    2017-05-19 21:04:44
    linux下的信号量本身就是临界资源,所以PV操作都是原子操作。 下面是实现二元信号量的代码,二元信号量就是互斥锁。 comm.h 1 #ifndef _COMM_H_ 2 #define _COMM_H_ 3 4 #include 5 #include 6 #include 7 #...
  • linux LVM逻辑卷管理

    2018-05-17 17:32:06
    t:修改分区类型,Linux LVM类型的代码是8e p:查看分区情况 w:保存分区表并退出 q:不保存退出 pvcreate /dev/sda1:创建pv pvs:查看pv vgcreate datavg /dev/sda1:创建vg vg...
  • ├<1 Linux操作系统基础> │ ├01 - 说在前面的话1.mp4 │ ├02 - 说在前面的话2.mp4 │ ├03 - 说在前面的话3.mp4 │ ├04 - 说在前面的话4.mp4 │ ├05 - 计算机组成原理概述1 .mp4 │ ├06 - 计算机组成原理概述2...
  • Linux下的进程通信(IPC)

    2012-11-30 01:03:29
    POSIX无名信号量 如果你学习过操作系统,那么肯定熟悉PV操作了.PV操作是原子  操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在CPU上面  执行.在系统当中,有时候为了顺利的使用和保护共享...
  • 实验内容没用PV操作代码程序的问题加了PV操作代码 实验内容 有一临界资源是一个建立在共享存储区的栈 服务进程 建立并初始化栈, 初始状态下共享栈满,里面顺序放置一系列正整数(自栈顶向下:1,2,3…), 可以与...
  • 前言:Linux下的进程通信(IPC) Linux下的进程通信(IPC)  POSIX无名信号量 ... 如果你学习过操作系统,那么肯定熟悉PV操作了.PV操作是原子操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在C
  • PV操作是原子操作.也就是操作是不可以中断的,在一定的时间内,只能够有一个进程的代码在 CPU 上面执行. 在系统当中,有时候为了顺利的使用和保护共享资源,提出了信号的概念. 假设使用一台打印机,如果在同

空空如也

空空如也

1 2 3 4
收藏数 72
精华内容 28
关键字:

linuxpv操作代码

linux 订阅