我有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信号量? 我是同步过程的新手。请我帮忙!
谢谢。
答案 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>
第三,您的代码中存在多个小怪异之处,包括
semop()
用作信号量密钥,否则通常通过IPC_PRIVATE
而不是使用固定的密钥ID来获取密钥。这有助于避免按键冲突。ftok()
的第四个参数应该是semctl
(根据文档,您必须定义自己),但是您正在传递union
。如果那看起来像您期望的那样起作用,那仅仅是因为您很幸运。int
执行IPC_RMID
操作来实现这一目的,或者在必要时通过在Shell中运行适当的semctl()
命令来实现。