使用3进程的System V信号量进行同步

时间:2018-06-28 15:12:53

标签: c process synchronization semaphore

我有3个进程,我想使用系统v信号进行同步。 进程1,2,3将数据写入单个文件。

进程1将A写入I, 流程2将a写入i, 进程3将1写入9。

我期望输出Aa1Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9。

过程1

#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
    int id,ret,fd;  
    char i;

    struct sembuf v;

    id=semget(8, 5, IPC_CREAT | 0644);
    if(id <0)
    {
        printf("wrong\n");
    }
    fd= open("sample1", O_RDWR | O_APPEND | O_CREAT,0644);

    v.sem_num = 1;
    v.sem_op = 0;
    v.sem_flg = 0;

    semctl(id, 1, SETVAL, 0);   
    semctl(id, 2, SETVAL, 0);   
    semctl(id, 3, SETVAL, 0);

    for(i='A';i<='I';i++)
    {
        semop(id,&v,1);
        semctl(id, 1, SETVAL, 1);
        semctl(id, 2, SETVAL, 1);
        semctl(id, 3, SETVAL, 1);       

        write(fd, &i, 1);

        semctl(id, 2, SETVAL, 0);
        semctl(id, 3, SETVAL, 1);
        semctl(id, 1, SETVAL, 1);
    }

    printf("Done...\n");    
}

过程2

#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>
int main()
{
    int id,ret,fd;  
    char i;

    struct sembuf v;

    id=semget(8,5, IPC_CREAT | 0644);
    if(id <0)
    {
        printf("wrong\n");
    }
    fd= open("sample1", O_RDWR | O_APPEND | O_CREAT, 0644);

    v.sem_num = 2;
    v.sem_op = 0;
    v.sem_flg = 0;

    for(i='a';i<='i';i++)
    {
        semop(id,&v,2); 
        semctl(id, 1, SETVAL, 1);
        semctl(id, 2, SETVAL, 1);   
        semctl(id, 3, SETVAL, 1);

        write(fd, &i, 1);

        semctl(id, 3, SETVAL, 0);
        semctl(id, 1, SETVAL, 1);
        semctl(id, 2, SETVAL, 1);
    }

    printf("Done...\n");    
}

过程3

#include<sys/types.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>

int main()
{
    int id,ret,fd;  
    char i;

    struct sembuf v;

    id=semget(8,5, IPC_CREAT | 0644);
    if(id <0)
    {
        printf("wrong\n");
    }
    fd= open("sample1", O_RDWR | O_APPEND | O_CREAT,0644);

    v.sem_num = 3;
    v.sem_op = 0;
    v.sem_flg = 0;

    for(i='1';i<='9';i++)
    {
        semop(id,&v,3); 
        semctl(id, 1, SETVAL, 1);
        semctl(id, 2, SETVAL, 1);   
        semctl(id, 3, SETVAL, 1);

        write(fd, &i, 1);

        semctl(id, 1, SETVAL, 0);
        semctl(id, 2, SETVAL, 1);
        semctl(id, 3, SETVAL, 1);
    }

    printf("Done...\n");    
}

预期输出为Aa1Bb2Cc3Dd4Ee5Ff6Gg7Hh8Ii9。但我没有得到正确的输出。请帮忙摆脱这个问题吗?

哪个系好?系统V信号量或POSIX信号量? 我是同步过程的新手。请我帮忙!

谢谢。

1 个答案:

答案 0 :(得分:0)

您在策略和实施方面似乎都遇到了一些问题。

首先,通过SysV信号量控制程序/线程进度的常用基本机制是,控制其进度的线程使用semop()来尝试减少信号量。

struct sembuf sb = { .semnum = 1, .sem_op = -1 };
int rval = semop(semid, &sb, 1);
// handle any error ...

这将阻塞,直到信号量的值足够大以继续进行(假设它永远不会低于零)。为了使该线程继续运行,其他线程(可能在不同的进程中)将使用semop()递增相同的信号量:

struct sembuf sb = { .semnum = 1, .sem_op = 1 };
int rval = semop(semid, &sb, 1);
// handle any error ...

此外,这种方法意味着设法锁定信号量(通过减小其值)的线程也会自动减少其他线程(或本身)锁定信号量的机会。安排信号量的值永远不会超过1时,这将使信号量功能递减,就像锁定互斥锁一样,而增加一个功能如解锁互斥锁则递增。

请注意,semctl()与这些位无关(尽管它将与预先设置信号量有关)。您应该将semctl()视为用于管理信号量的管理界面,而不是作为常规信号量操作的界面。

第二,您在信号量初始化方面遇到问题。它仅由进程1执行,但是您什么也没做,无法确保进程1在其他进程开始尝试使用信号量集之前完成其初始化。原来这是SysV信号量中最有问题的方面之一。

解决这个问题的一种方法是让启动器设置并初始化信号量集,然后启动真正使用它的三个进程(然后再不进行初始化)。

如果您可以依靠最初不存在的信号量集(这对您来说是有问题的,因为您使用了固定键并且从不删除信号量集),那么您的进程除了可以使用O_EXCL标志{1}}当他们打电话给O_CREAT时。那只会在其中一个过程中成功,然后它可以负责初始化信号量。其他人在没有semget()的情况下执行新的semget(),然后等待初始化完成。他们可以通过用O_EXCL轮询semctl()来实现,以查看信号量的IPC_STAT变为非零,这将在初始化线程第一次执行otime时发生。 / p>

第三,您的代码中存在多个小怪异之处,包括

  • 您请求一个5成员信号量集,但只能使用3。
  • 信号量集的成员从0开始编号,但是您使用的最低信号量数是1。
  • 除非您将semop()用作信号量密钥,否则通常通过IPC_PRIVATE而不是使用固定的密钥ID来获取密钥。这有助于避免按键冲突。
  • 给定后,ftok()的第四个参数应该是semctl(根据文档,您必须定义自己),但是您正在传递union。如果那看起来像您期望的那样起作用,那仅仅是因为您很幸运。
  • 使用信号灯完成最后一个过程后,应将其删除。您可以通过对int执行IPC_RMID操作来实现这一目的,或者在必要时通过在Shell中运行适当的semctl()命令来实现。
  • 您应该检查提供了一个的每个函数调用的返回码,除非您真的不在乎它是否成功。