当前位置:  技术问答>linux和unix

不规则的多进程读些同步问题

    来源: 互联网  发布时间:2016-05-15

    本文导语:  各位高手:     我在工作中遇到了一个问题,Linux下的多进程读些同步,说不太规则,是说:教科书上的进程同步,都是读写分别属于不同进程,读进程里只有读,写进程里只有写,但我碰到的情况如下: 两个程序...

各位高手:
    我在工作中遇到了一个问题,Linux下的多进程读些同步,说不太规则,是说:教科书上的进程同步,都是读写分别属于不同进程,读进程里只有读,写进程里只有写,但我碰到的情况如下:
两个程序配合
1 甲程序里父进程fork()出的每个子进程都先读共享内存A区,如果在共享内存A区里没找到所需内容所需数据就查找数据库,查到后到了就写到A区共享内存里(次序一定,必定是先读后写),再读写B内存,同样,B区里没找到所需内容所需数据就查找数据库,查到后到了就写到B区共享内存里( 也是先读后写),
子进程1…..n流程如下:
if (-1 == readAmem()) //返回-1表明内存A区里没找到
    writeAmem ();//写A内存
.
//再接着读另外一块共享内存B .
if(-1==readBmem())// 返回-1表明内存B区里没找到
     writeBmem();,//写B内存

2 乙程序配合甲程序:乙程序是单个进程,只有写内存,不读,乙程序等待键盘输入,通过手工输入命令行决定写A还是写B内存,一次只输一个命令,即一次只写一块内存,因为不能保证执行写内存时没有甲程序的子进程在读写同一块内存,所以也需要保护措施
.
//乙程序通过一个命令行写共享内存A区,   
writeAmem ();//写A内存  
// 输入另外一个命令,则写共享内存B区,   
writeBmem();//写B内存  
         
要求:1甲程序的任意多的子进程可以同时读A或者B内存,
2 一次只有一个进程(这个进程既可以是甲程序的也可能是乙程序的)可以往数据区A写,但同时可以有另外一个进程往另外一个数据区B里写,同理,一次只有一个写进程可以往数据区B写,但同时可以有另外一个进程往另外一个数据区A里写
3 如果一个进程正在往数据区A中写, 禁止任何进程读数据区A,但允许其他进程读另外一个数据区B,也允许另外的子进程写另外一个数据区B

总结:即:各进程在同一块内存区“读-写” 互斥;“写-写” 互斥;“读-读” 允许,但各进程在不同的内存区“读-写”, “写-写”,“读-读”都允许

我参考了线程同步的方法,觉得规则的进程同步方法也适用于这个看似不规则的问题,用信号量解决如下:

/*为同步访问访问共享内存A,设置三个互斥信号量:
3 rwmutex        用于写者与其他读者/写者互斥的访问共享内存A
4 rmutex        用于读者互斥的访问读者计数器信号量6
5 nrmutex        用于写者等待已进入读者退出,所有读者退出前互斥写操作
6   读者计数器
初始化四个信号量:var   rwmutex,rmutex,nrmutex:semaphore:=1,1,1;6 = 0*/
甲程序的每个子进程里设置同步措施如下:
以下粗斜体字为行号

//读共享内存A,即readAmem()函数里:
L1 semop(semid, &p3, 1);    //    P(rwmutex); 
L 2 semop(semid, &p4, 1);   //  P(rmutex); 互斥的访问读者计数器信号量6
L 3 semop(semid,&v6,1);// readcount++;
L 4     if (1 == semctl(semid, 6, GETVAL,0)) //if (readcount == 1)
L 5         semop(semid,&p5,1); //P(nrmutex);  //有读者进入,互斥写操作
L 6 semop(semid, &v4, 1);      //  V(rmutex);
L7 semop(semid, &v3, 1); // V(rwmutex);  //及时释放读写互斥信号量,允许其它读、//写进程申请资源读数据;

L 8  fprintf(stderr, " %ld 子进程 READ A SHM................Begin!n", pid);
…….
L 9 fprintf(stderr, " %ld 子进程 READA SHM........Over!n", pid);

L 10 semop(semid, &p4, 1);//       P(rmutex);
L 11 semop(semid,&p6,1);//readcount--;
L 12 if (0 == semctl(semid, 6, GETVAL,0))
L 13         semop(semid,&v5,1); //V(nrmutex);  //所有子进程读完A,允////许写更新
L 14  semop(semid, &v4, 1); //     V(rmutex);

//if (-1 == readAmem())//则进入写A内存函数//writeAmem (),如下:
L 15 semop(semid,&p3,1);// P(rwmutex);    //互斥后续其它读者、写者
L 16 semop(semid,&p5,1);// P(nrmutex);    //如有读者正在读A内存,等待所有//读者读完

L 17 fprintf(stderr, " %ld 子进程 write A SHM............Begin!n", pid);
……………….
L 18 fprintf(stderr, " %ld 子进程 write A SHM..........Over!n", pid);//写//更新;
L 19  semop(semid,&v5,1);//V(nrmutex);    //允许后续新的第一个读者进入后//互//斥写操作
L 20 semop(semid,&v3,1);//V(rwmutex);    //允许后续新读者及其它写者
接下来,甲程序的子进程进入读写B内存
同理:对于同步访问B共享内存,方法和同步访问A共享内存原理完全一样
/*设置另外三个互斥信号量:
7 rwmutex        用于写B内存时与其他读者/写者互斥的访问共享内存B
10   已在读B内存的子进程计数器
8 rmutex        用于读者互斥的访问读B内存的计数器---信号量10
9 nrmutex        用于写B内存时等待已进入读B内存的所有子进程退出,所有读B退出前互斥写B操作
var   rwmutex,rmutex,nrmutex:semaphore:=1,1,1;10 = 0*/

//读共享内存B,即readBmem()函数里:
L 21 semop(semid, &p7, 1);    //    P(rwmutex);
L 22 semop(semid, &p8, 1); //P(rmutex);用于互斥的访问读者计数器信号量10
L 23 semop(semid,&v10,1);// readcount++;
L 24 if (1 == semctl(semid, 10, GETVAL,0)) //if (readcount == 1)
L 25    semop(semid,&p9,1); //P(nrmutex);  //有读者进入,互斥写操作
L 26 semop(semid, &v8, 1);      //  V(rmutex);
L 27 semop(semid, &v7, 1);    //   V(rwmutex);  //及时释放读写互斥信号量,允许//其它读、写进程申请资源读数据;

L 28 fprintf(stderr, " %ld 子进程read B SHM...........Begin!n", pid);

L 29 fprintf(stderr, " %ld 子进程read B SHM...........Over!n", pid);

L 30 semop(semid, &p8, 1);//       P(rmutex);
L 31 semop(semid,&p10,1);//readcount--;
L 32 if (0 == semctl(semid, 10, GETVAL,0))   // if(readcount == 0)
L 33 semop(semid,&v9,1); //V(nrmutex);  //所有读者退出,允许写更新
L 34  semop(semid, &v8, 1); //     V(rmutex);

//if (-1 == readBmem())/则进入写共享内存函数//writeBmem()
L 35 semop(semid,&p7,1);// P(rwmutex);    //互斥后续其它读/写B内存
L 36    semop(semid,&p9,1);// P(nrmutex);    //如有读B内存的子进程//正在读,等待所有读者读完

L 37 fprintf(stderr, " %ld 子进程write B SHM..........Begin!n", pid);
。。。。。。
L 38 fprintf(stderr, " %ld 子进程write B SHM...........Over!n", pid);

L 39   semop(semid,&v9,1);//V(nrmutex); //允许后续新的第一个读者进入后互斥写B内存操作
L 40 semop(semid,&v7,1);//V(rwmutex); //允许后续新读者及其它写者

以上是甲程序的子进程,对于乙程序,等待手工输入的命令行刷新A或者B共享内存,写A内存时同步措施同甲程序的writeAmem()中的一样,如下L41---L46 
L41 semop(semid,&p3,1);// P(rwmutex);    //互斥后续其它读者、写者
L 42 semop(semid,&p5,1);// P(nrmutex);    //如有读者正在读A等待所有//读者读完

L43 fprintf(stderr, " 乙进程 write A SHM............Begin!n");
……………….
L 44 fprintf(stderr, "乙进程 write A SHM..........Over!n");//写//更新;
L 45  semop(semid,&v5,1);//V(nrmutex);    //允许后续新的第一个读者进入后//互//斥写操作
L 46 semop(semid,&v3,1);//V(rwmutex);    //允许后续新读者及其它写者


同理:乙程序刷新B内存时同步措施同writeBmem()中的一样,如下L51---L56
L51 semop(semid,&p7,1);// P(rwmutex);    //互斥后续其它读/写B内存
L52    semop(semid,&p9,1);// P(nrmutex);    //如有读B内存的子进程//正在读,等待所有读者读完

L53 fprintf(stderr, "乙进程 write B SHM ..........Begin!n", pid);
。。。。。。
L 54 fprintf(stderr, "乙进程 write B SHM...........Over!n", pid);

L55   semop(semid,&v9,1);//V(nrmutex); //允许后续新的第一个读者进入后互斥写8583field内存操作
L 56 semop(semid,&v7,1);//V(rwmutex); //允许后续新读者及其它写者

几种进程同步次序情景分析:
情景一:
1 设甲程序开的子进程1先运行完L1行, 3#信号量由1变为0,接着往下运行,在子进程1运行完L7之前,此时若乙程序运行L41行,或是再有子进程2….n再运行L1行,则都将使3#信号量变为负数,则乙程序被阻塞在L41行,甲程序的子进程都将依次被阻塞在readAmem()函数的L1行,系统依次将被阻塞的子进程的标志放入3#信号量的阻塞队列里(队列,意味着唤醒时先进者先出),
 
2 子进程1在L2—L6的操作中,使得表示正在读A内存的子进程的计数器---6#信号量加1,5#信号量的值由1变为0,表明有子进程正在读A内存,子进程1做完L7行,使3#信号量的值加1,唤醒3#信号量的阻塞队列里下一个进程,假设下一个进程是乙程序的L42行,再有子进程企图运行L1行,都一律被3#信号量堵塞,此时有乙程序和子进程1两个进程都是活跃的,有两种可能
A 假设系统安排先继续运行乙程序运行到第L42行,5#信号量的值由0变为-1,还没来得及做L43写A内存再次被阻塞,乙进程的标志放入5#信号量的阻塞队列里,
子进程1继续运行L8-L9读A内存,读完后在L14行唤醒乙进程,乙进程写完A内存后,L46行v3操作唤醒下一个3#信号量的阻塞队列里的进程

B 假设系统安排先继续运行子进程1的L8-L9读完A内存,只要子进程1先做完L13的 V5操作 ,使得5#信号量由0变1,则系统再调度运行乙进程第L42行,P5操作,乙进程不再堵塞,写A内存,但此时不再有子进程读A内存,不会冲突,反之,如果乙程序L42行先于子进程1的L13的 V5操作,则乙写B内存的进程被堵塞

情景二:
1 如果乙程序写A内存的进程的L41的P3操作抢在子进程1的L1之前先做,3#信号量由1变为0,接着往下运行,在乙运行完L46之前,此时若再有子进程2….n再运行L1行,子进程都将依次被阻塞在readAmem()函数的L1行,直至乙程序写完A内存后运行完L46,唤醒子进程

情景三:
上面两种情境都考虑了子进程运行时有人手工输入命令而启动的写内存的乙程序的参与,如果子进程启动时没有乙程序的打扰,
1 设甲程序开的子进程1先运行完L1, 3#信号量由1变为0,接着往下运行,在子进程1运行完L7之前,再有子进程2….n再运行L1行,则都将使3#信号量变为负数,子进程都将依次被阻塞在readAmem()函数的L1行,系统依次将被阻塞的子进程的标志放入3#信号量的阻塞队列里(队列,意味着唤醒时先进者先出),
2 子进程1做完L7行,使3#信号量的值加1,唤醒3#信号量的阻塞队列里下一个子进程2,此时两个子进程都是活跃的,同理,子进程2做完L7行,使3#信号量的值加1,唤醒3#信号量的阻塞队列里下一个子进程3(如果子进程3存在),此时3个子进程都是活跃的,………则这表明n 个子进程同时读A内存是允许的,同时读A内存的子进程个数由每个子进程的L3行统计
3 一旦有某子进程读完,就在L11减少读A内存的子进程个数
4一旦有某子进程读完率先进入writeAmem() 函数, 运行L15行P3操作,此时情况等同于情境一第一步,只不过情境一里的乙进程被现在的某子进程的writeAmem() 函数代替,可参阅情景一
  

至于另外一个共享内存B,因为其读/写与A内存完全不存在同步的必要,则可换另外一套信号量7-10,步骤完全一样


不知各位高人看出我的解决方案有什么疏漏吗?请不吝指正!多谢!

|
太长了,看了第一段,进程间互斥用记录锁吧。

|
记录锁不一定就是用来锁文件,进程间互斥一般就是用记录锁的。定义一个空文件就可以了。

至于你这里的共享内存,同样是可以用记录锁的,共享内存其实就是读入一个文件的内容到一块物理内存,然后把这块物理内存映射到不同进程的内存空间里去。所以用记录锁来互斥这块共享内存是一个很好的选择。

|

也可以解决你的问题,比如在writeAmem()入口处对文件加锁,然后在退出这个函数之前对这个文件解锁。同样在读A内存的函数里面也做同样的处理就可以实现同步。

|
你如果采用多进程的用信号量的方式或是采用多线程用互斥锁的方式都不好对同一块内存的不同区域进行加解锁。

况且多进程互斥就是使用文件锁,信号量是用来同步的。互斥与同步看似相同,仔细一想差别还是很大的。

|
分析好长啊,感觉你的进程间需求挺多的,锁别搞那么复杂,文件互斥锁吧。

|
锁保护的不是代码,而是临界区数据,我觉得比较适合使用advisory lock。

    
 
 

您可能感兴趣的文章:

  • 信号灯同步2个进程,一个进程如何主动给另一个进程发送通知?
  • 进程同步问题
  • 用信号量机制解决实际的三个进程同步问题
  • 关于进程同步
  • linux进程同步或互斥
  • 请问在子进程中变量如何与父进程同步(100)
  • 进程同步,用进程+SYS V信号量实现如下前趋图
  • linux下进程同步有mutex吗?
  • 两个不同的进程对共享内存中的变量读写,一般通过什么方式同步方便?
  • 请问pthread_mutex_lock()和pthread_mutex_unlock()可不可以用于对不同进程的线程进行同步。
  • 请问在单进程,多线程程序里,线程间使用IPC的信号量来同步,能行吗?
  • 求一个多进程之间的同步算法?
  • 进程数据同步:消息队列还是共享内存+信号
  • 进程间通信:pthread_cond使用在线程间,我要进程间条件同步(没有情缘关系的进程),采用什么方呢?也就是说我要在UNIX实现WIN32上命名Event的功能
  • 使用TSL命令实现进程同步和互斥来防止竞争条件!
  • 关于进程的创建和同步
  • apue中父子进程同步的问题。
  • Unix下共享内存一个写N个读的进程同步与互斥
  • linux下多进程访问共享内存队列同步的问题
  • posix 无名信号量 实现进程间同步 失败 sem_init sem_wait sem_post
  • 多进程问题 子进程读取内容 读完挂起,父进程写 写入后唤醒子进程
  • 请教,进程通讯问题,除了父子进程能进行通讯外,任意两个进程都可以吗?
  • 父进程退出后子进程的问题
  • 僵死进程父进程的问题
  • 求教 "客户进程" 与 "守护进程" 间通信问题
  • 子进程与父进程通信问题?急
  • 一个关于父进程和子进程的问题
  • 请教一个关于子进程和父进程竞争的问题
  • 多个进程共用一个信号量,如果某个进程死掉,此时又将信号量锁定,其它进程就死掉,有什么办法可以解决这一问题
  • 求教一个关于子进程与父进程socket描述符的一个问题
  • 请教:进程创建和进程状态有关问题
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • linux僵尸(zombie)进程介绍及清除
  • 进程Afork进程B,进程Bfor进程C,如果进程C退出发出SIGCHLD,A进程是否可以收到
  • Ubuntu查看内存,进程相关命令介绍
  • 如果一个server进程要fork许多子进程,但不等待子进程终止,也不希望子进程结束后处于僵进程状态直到父进程终止。请问可采用什么方法实现
  • linux下进程占用内存空间详解
  • 在多进程中父进程frok子进程,怎样让子进程自举,脱离父进程,而且父进程不退出
  • Linux进程的内核栈和用户栈概念,相互关系及切换过程
  • fock()开出的子进程的进程ID是否进程ID都大于父进程的?
  • android 4.0 托管进程介绍及优先级和回收机制
  • 父进程等待子进程n秒,如果子进程正常退出,父进程立即继续向下执行,如果子出现进程故障一直不退出,父进程等待n秒后继续向下执行,请问
  • linux下进程间通信:共享内存原理及具体用法举例(基于c/c++语言)
  • Web服务器/前端 iis7站长之家
  • 我在一个父进程中,生成了4个子进程,子进程的优先级是一样的。我现在想结束子进程。该如何做?
  • 子进程wait/waitpid//子进程不结束,父进程会等待子进程吗?
  • 在一个进程中我定义了几个全局变量,然后我又fork了几个子进程,子进程中是否可以各自对全局变量进行修改,如果各子进程都对其进行修改,
  • 怎样一次杀掉父进程创建的所有子进程?我在父进程中用kill(0,SIGKILL),结果父进程也给干掉了,参数0难道不是表示除自己外的所有同uid的进
  • 进程创建进程组后,然后创建该组中的进程,然后终止。这里的终止....?
  • 如何实现子进程根据父进程的信号来确定是否终止子进程???
  • 高手请教!linux怎样通过pid获取进程信息,如:进程名、进程状态等?
  • 如何通过进程号获得进程的一些信息,例如:进程运行的目录
  • 【如何彻底杀死子进程】Kill -9子进程后进程呈僵死状态


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3