当前位置: 首页 > 知识库问答 >
问题:

父进程在子进程之前执行,如何通过信号量强制相反?

夏景同
2023-03-14

我在Unix C中使用共享内存、信号量和分叉时遇到了困难。我的信号量不是POSIX。我创建一个指向共享html" target="_blank">内存2*sizeof(float)的指针。我用semctl将信号量的值初始化为2。我在for循环(I<2)中执行fork()。在子进程中(如果fork()==0),每个子进程对信号量(-1)执行p操作,写入共享内存,然后执行v操作(+1),然后退出。父进程对信号量执行p操作(-2),读取整个共享内存段(使用for循环),并执行v操作(+2)。他在离开前等待孩子进程,以避免僵尸。我在输出中遇到的问题是:

 Parent reading 0
 Parent reading 1
 Parent reading 0
 Parent reading 1
 Child writing 0
 Child writing 1

当我应该得到的是:

 Child writing 0
 Child writing 1
 Parent reading 0
 Parent reading 1

我尝试将信号量初始化为1,而不是2,但这只会阻碍程序,因为信号量的值永远不会为2,因此父进程永远不会读取。

/** OPEN MEMORY **/

int shmid1 = shmget(1990, (size),  IPC_CREAT | 0666 ); 

float * shmPt = (float*)shmat(shmid1, NULL, 0);    

/** CREATE INITIALIZE SEMAPHORE **/   

semun1.val = 2;

int semid = semget(1991, 1, 0666 | IPC_CREAT)

semctl(semid, 0, SETVAL, semun1 )


  /**  CREATE PROCESSES **/
  for ( ii = 0; ii < 2; ++ii) {
    if ((p = fork()) == 0) {

      int semid = semget(1991, 1, 0666);

      struct sembuf p_buf;

      p_buf.sem_num = 0;p_buf.sem_op = -1;p_buf.sem_flg = SEM_UNDO;
      /** LOCK **/ 
      semop(semid, &p_buf,1);
      /** WRITE **/
      shmPt[ii] = RandomFloat;

      v_buf.sem_num = 0;v_buf.sem_op = 1;v_buf.sem_flg = SEM_UNDO;
      /** UNLOCK **/
      semop(semid, &v_buf,1) 

      exit(0);
    }
    else {

      int semid = semget(1991, 1, 0666);

      struct sembuf p_buf;

      p_buf.sem_num = 0;p_buf.sem_op = -2;p_buf.sem_flg = SEM_UNDO;
      /** LOCK **/ 
      semop(semid, &p_buf,1);
      /** READ **/
      for(int j =0;j<2;j++) tabFloat[j] = shmPt[j];

      v_buf.sem_num = 0;v_buf.sem_op = 2;v_buf.sem_flg = SEM_UNDO;
      /** UNLOCK **/
      semop(semid, &v_buf,1) 

    }
}

共有1个答案

马丰
2023-03-14

你错误地使用了信号量。一般的想法是,信号量计算“现在允许多少实体(线程,无论什么)使用该数据”。通过从2开始计数,您表示“现在有两个线程可能会使用这个”。信号量不说哪些实体,也不说如何(读写),只说多少个实体。例如,信号量可以用于计算生产者/消费者队列中可检索项的数量:生产者递增,消费者递减。(当然,信号量有各种各样的扩展形式;因为您说这些“不是POSIX”,但不是它们本身,所以很难概括更多。)

实现上述工作的一种方法--当然,实际代码往往会因描述而异--是从0开始信号量计数,分叉一个子,让该子在不查看信号量计数的情况下写入,分叉另一个子,让该子也在不查看信号量计数的情况下写入,然后让父等待信号量(P)。也就是说,信号量说“没有人会通过”,但孩子们实际上并不看它。然后,这两个孩子各自做V个运算(每一个+1个)。一旦信号量变为1,父级开始:然后他可以找到至少一个(但可能只有一个)子级结果。如果需要同时得到两个结果,家长可以立即做另一个P。

(不过,更一般地说,您可能需要读写器锁或互斥锁和条件变量。如果您有POSIX线程,请参见pthread_cond_init()pthread_cond_wait()pthread_cond_signal()pthread_mutex_init()等。)

啊哈,从注释和问题编辑中,我看到您使用的是糟糕的System V共享内存和信号量接口

  • 你真的被那个卡住了吗?在我看来,POSIX线程更好(而且通常重量更轻)。
  • 您打算如何组织共享内存?如果每辆车都有自己的圈速区域,并且只与display Thread/proc共享,那么锁争用可能会减少:只有一个生产者(汽车)和一个消费者(display Thread/proc),但有24个这样的锁(每辆车一个)。如果所有汽车与显示线程/proc共享一个共享内存区域,则只需要一个锁,但它的活动性要高得多。哪一个“更好”取决于你在做什么。
  • 并且,如果您想等待“某辆车跑完50圈”,可以考虑让每辆车都有自己的专用(或共享显示)计数器,以及一个用于“跑完50圈的车数”的计数信号量。每辆车只需向上计数,当达到50时,计数信号量也会增加(一次)。

最后(我希望)编辑:在修复了较小的问题之后,剩下的最后一个问题是在每个子进程中使用sem_undo,这将执行一个V(of+1)来表示“数据产生并全部完成”,然后exitsem_undo记录进程退出时应用的平衡调整值,因此信号量将向上计数,但随后立即向下计数,让父级等待另一个永远不会出现的V。

 类似资料:
  • 本文向大家介绍python执行子进程实现进程间通信的方法,包括了python执行子进程实现进程间通信的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python执行子进程实现进程间通信的方法。分享给大家供大家参考。具体实现方法如下: a.py: b.py: 希望本文所述对大家的Python程序设计有所帮助。

  • 问题内容: 是否可以从Shell脚本中的父进程ID获取子进程ID? 我有一个要使用Shell脚本执行的文件,这会导致一个新进程 process1 (父进程)。这个 过程1 已经分叉的另一个进程 过程2 (子进程)。使用脚本,我可以使用以下命令获取 process1 的pid : 但我无法获取子进程的pid。 问题答案: 只需使用:

  • 是否可以从外壳脚本中的父进程ID获取子进程ID? 我有一个要使用shell脚本执行的文件,这会导致一个新的进程process1(父进程)。此进程1已经派生了另一个进程process2(子进程)。使用脚本,我可以使用以下命令获得进程1的pid: 但是我无法获取子进程的pid。

  • 使用在python中,我试图运行一个perl脚本,它在远程机器上运行一个代码来获取一些信息。 我在机器A上有两个脚本—python和perl。python脚本使用方法。两个脚本都运行得很好。 但是,perl脚本是按串行顺序执行的(一个接一个的IP)。 实际行为- python脚本通过传递'198.168来运行perl脚本。1.2' perl脚本执行代码并Hibernate15秒 python脚本然

  • 问题内容: 我正在用Go编写负载平衡的服务器系统。 负载平衡服务器将与多个应用程序服务器通信并处理请求。这些服务器都可以在同一台计算机或网络上运行。 我已经找到了网络,但是现在我需要找到一种最佳的方式来使负载均衡器与本地应用程序服务器进行通信。使用-networking似乎并非最佳选择。 我正在尝试通过和系统调用共享内存,但是没有找到任何有效的示例,并且该软件包也完全没有文档说明。 有人可以为我提