2013-05-26 41 views
0

我用我的信号灯不POSIX共享内存,信号量和在unix下叉有麻烦。 我创建了一个指向共享内存2 * sizeof(float)的指针。 我用semctl将我的信号量的值初始化为2。 我在for循环中做了一个fork()(i < 2)。 在子进程(如果叉()== 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) 

    } 
} 

编辑: 我的最终目标是让24个孩子写一个接一个成相同大小的共享内存段,并且只当它是满的,那么家长可以读到的一切和处理信息。最重要的是,所有这些都需要处于一段时间的循环中(想象一下,每次完成一圈,每次完成一圈的24辆汽车会持续产生,直到第一辆车完成50圈)

+0

相反_describing_的代码,为什么不是_show_给我们?当你看到并理解你所做的事时,会更加容易。 –

+0

而不是试图描述你的代码,为什么不只是发布你的代码? (在一个简化的形式,如果必要的。) –

+0

我加入了简化代码 – user1895293

回答

4

您错误使用信号量。总的想法是,信号量会计算“现在有多少实体(线程,无论什么)被允许使用这些数据”。通过开始计数2,你说“两个线程现在可以使用它”。信号量不说其中实体,也不是如何(读vs写),只有多少。例如,可以使用信号量来计算生产者/消费者队列中可检索项的数量:生产者增量和消费者递减量。 (当然,信号灯进来各种扩展的味道;因为你说的这些都是“没有POSIX”,但不是他们,很难一概而论等等。)

的一种方法,使这项工作作为描述,但是,当然,实际代码趋向于从变化描述-是在0至启动信号计数,叉子,有孩子的写不看信号计数,叉另一个孩子,有儿童也写不看信号计数,然后让父母等待信号(P)。也就是说,信号量说“没有人会通过”,但孩子们实际上并没有看到它。然后,两个孩子每个都做V操作(每个+1)。一旦信号量达到1,父母开始:他可以找到至少一个(但也许只有一个)孩子结果。如果父母需要同时有两个结果,父母可以立即做另一个P.

(更普遍,不过,你可能想读/写锁或互斥体和条件变量。如果你有POSIX线程,请参见pthread_cond_init()pthread_cond_wait()pthread_cond_signal()pthread_mutex_init()等)


啊哈,在征求意见和问题编辑,我看到你正在使用的猥琐System V共享内存和信号灯接口。

  • 你真的坚持吗?在我看来,POSIX线程更好,并且通常更轻量级。
  • 你打算如何组织你的共享内存?如果每辆车都有自己的单圈时间区域,只与显示线程/ proc共享:有一个单一的生产者(汽车)和一个单一的消费者(显示线程/ proc),您可能获得更少的锁争用,但是24个这样的锁每车一个)。如果所有汽车与显示线程/ proc共享一个共享内存区域,则只需要一个锁,但它更加活跃。哪一个“更好”取决于你在做什么。
  • 而且,如果你想等待“一些汽车完成50圈”,请考虑每款车都有自己的私人(或可能共享与显示器)柜台,并为“有车数量的一个计数信号命中50圈“。每辆汽车简单地计数并达到50时,计数信号量也会增加(一次)。

决赛(我希望)编辑:固定小问题之后,最后剩下的一个是在每个子进程使用SEM_UNDO,它会做一个V(+1)的信号“产生的数据并全部完成“,然后exitSEM_UNDO记录了在进程退出时应用的平衡调整值,所以信号量会计数,但是会立即计数,让父母等待另一个永远不会发生的V.

+0

我明白你在说什么,但我最终的目标是拥有24个孩子写一个接一个成相同大小的共享内存段,当它是唯一的全,那么父母可以读取所有内容并处理信息。除此之外,所有这些都需要在一段时间内完成(想象一下24辆赛车每次完成一圈时都会产生随机时间,直到第一辆赛车完成50圈)。 – user1895293

+0

是的,我害怕我被卡住了。当我分叉for循环24次时,我将'i'作为参数传递给每个子进程,并且每个进程都在共享内存中写入不同的地方。因此进程0正在写入shmPt [0]等等。我只想让所有24个人一个接一个地写,然后消费者在所有孩子写完所有内容之后一次性阅读所有内容,并根据需要循环多次,我需要一种方法来用信号量做到这一点。 – user1895293

+0

顺便说一句每节车厢已经拥有自己的私人圈计数器和每个一圈后我排序的数组找到最快的赛车,并检查其搭接计数器,在主while循环的MAXLAPS不断比较。 – user1895293

相关问题