我正在尝试创建一个从0到C中命令行输入的数字的程序。在这个程序中,必须有两个fork()调用,总共有3个进程。然后我必须使用至少1个信号量来确保进程按数字顺序运行,每个进程负责不同的n%3。
我遇到的问题是,尽管我使用的是信号量,但该程序似乎在相当规律的基础上无序运行。我目前正在使用门式系统,其中每个进程都会强制它自己指定的信号量等待,一旦完成,sem_post应该在下一个运行的进程的信号量。我知道这不是最漂亮或最有逻辑效率的方法,但是在我前两次尝试同样的问题后,我非常肯定会这样做。
如果有人能就我错误的地方给我任何建议,我会非常感激。
我的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>
#define SEM_NAME1 "/sem1.mutex"
#define SEM_NAME2 "/sem2.mutex"
#define SEM_NAME3 "/sem3.mutex"
int main(int argc, char *argv[]) {
if(argc <= 1){
printf("No arguments were provided so there is no number to count to");
return 1;
}
// Create the 3 semaphores needed
sem_t *sem1;
sem_t *sem2;
sem_t *sem3;
//initialize to 0
sem1 = sem_open(SEM_NAME1, O_CREAT, O_RDWR, 0);
if (sem1==SEM_FAILED) {
printf("%s sem_open failed!", SEM_NAME1);
return (-1);
}
//initialize to 1
sem2 = sem_open(SEM_NAME2, O_CREAT, O_RDWR, 1);
if (sem2==SEM_FAILED) {
printf("%s sem_open failed!", SEM_NAME2);
return (-1);
}
//initialize to 1
sem3 = sem_open(SEM_NAME3, O_CREAT, O_RDWR, 1);
if (sem3==SEM_FAILED) {
printf("%s sem_open failed!", SEM_NAME3);
return (-1);
}
pid_t pid;
pid_t pid2;
pid = fork();
if(pid == 0){
pid2 = fork();
}
// Shared fork variables
int counter = 0;
int ranOnce = 0;
int max_num = atoi(argv[1]);
while(counter <= max_num){
if(pid > 0){
printf("%d",getpid());
if(ranOnce == 0){
counter += 1;
ranOnce = 1;
}
sem_wait(sem2);
printf(" %d \n", counter);
counter += 3;
sem_post(sem3);
}
else if(pid2 == 0){
printf("%d",getpid());
if(ranOnce == 0){
counter += 0;
ranOnce = 1;
}
sem_wait(sem1);
printf(" %d \n", counter);
counter += 3;
sem_post(sem2);
}
else{
printf("%d",getpid());
if(ranOnce == 0){
counter += 2;
ranOnce = 1;
}
sem_wait(sem3);
printf(" %d \n", counter);
counter += 3;
sem_post(sem1);
}
}
//sem_unlink(SEM_NAME1);
//sem_unlink(SEM_NAME2);
//sem_unlink(SEM_NAME3);
return 0;
}
答案 0 :(得分:2)
信号量初始值必须是反向
sem1 = sem_open(SEM_NAME1, O_CREAT, O_RDWR, 1);
sem2 = sem_open(SEM_NAME2, O_CREAT, O_RDWR, 0);
sem3 = sem_open(SEM_NAME3, O_CREAT, O_RDWR, 0);
您当前正在同时激活sem2和sem3进程,因此它们可以同时工作,但您需要同步它们以删除无序事件。
答案 1 :(得分:0)
抱歉,您的代码无法正常使用。
在fork
来电之后,每个进程都有自己的私有副本&#34;共享&#34;变量。与线程不同,您必须使用通过SysV共享内存原语设置的共享内存区域。
因此,每个进程都在递增自己的副本,而不是 counter
的共享副本。
此外,对共享变量的所有访问[包括while
子句]必须封装在锁中。
我不确定你是否在第三句中暗示我想使用共享变量,或者我应该使用单独的副本。
我在看你的评论:// Shared fork variables
,所以我推断你想要一个普通的计数器。 IMO,你做想要一个作为交叉检查
我知道每个人只访问他们自己的计数器变量副本,这就是信号量门的目的。当允许线程再次运行时,这意味着其他进程都已完成打印,因此序列中的下一个字符将比计数器的当前值提前3个。
我已经重新编写了您的应用以简化它,以便我能理解它。
我没有看到干净的循环序列。如果你现在,一切都很好,我可能已经介绍了一个bug。我使用shmget
et添加了一个共享内存全局计数器。人。它应该增加一个,但它偶尔会向后滑动[警告:它已经很晚了,我累了,所以这可能是问题的一部分: - )] < / p>
无论如何,这是我想出的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SEM_NAME1 "/sem1.mutex"
#define SEM_NAME2 "/sem2.mutex"
#define SEM_NAME3 "/sem3.mutex"
typedef struct tsk {
int tsk_idx;
sem_t *tsk_sem;
pid_t tsk_pid;
char tsk_name[100];
} tsk_t;
#define NTASK 3
tsk_t tsklist[NTASK];
// Shared fork variables
volatile int counter = 0;
volatile int ranOnce = 0;
int max_num;
volatile int *globptr;
void
dochild(tsk_t *tsk)
{
int stopflg;
int tidx;
tsk_t *tsk2;
while (1) {
sem_wait(tsk->tsk_sem);
stopflg = (counter > max_num);
if (! stopflg) {
printf("Tidx:%d Pid:%d Seq:%d",tsk->tsk_idx,tsk->tsk_pid,*globptr);
*globptr += 1;
if (ranOnce == 0) {
counter += 1;
ranOnce = 1;
}
printf(" Counter:%d\n", counter);
fflush(stdout);
counter += 3;
}
tidx = tsk->tsk_idx + 1;
tidx %= NTASK;
tsk2 = &tsklist[tidx];
sem_post(tsk2->tsk_sem);
if (stopflg)
break;
}
exit(0);
}
int
main(int argc, char *argv[])
{
tsk_t *tsk;
int tidx;
void *sptr;
if (argc <= 1) {
printf("No arguments were provided so there is no number to count to\n");
//return 1;
}
else
max_num = atoi(argv[1]);
int shmfd = shmget(IPC_PRIVATE,sizeof(int),0600);
sptr = shmat(shmfd,NULL,0);
globptr = sptr;
*globptr = 0;
// Create the 3 semaphores needed
for (tidx = 0; tidx < NTASK; ++tidx) {
tsk = &tsklist[tidx];
tsk->tsk_idx = tidx;
sprintf(tsk->tsk_name,"/sem%d.mutex",tidx);
if (max_num == 0) {
sem_unlink(tsk->tsk_name);
continue;
}
tsk->tsk_sem = sem_open(tsk->tsk_name, O_CREAT, O_RDWR,
0644,(tidx == 0) ? 1 : 0);
if (tsk->tsk_sem == SEM_FAILED) {
printf("%s sem_open failed! -- %s\n",tsk->tsk_name,strerror(errno));
return (-1);
}
}
if (max_num == 0)
return 0;
for (tidx = 0; tidx < NTASK; ++tidx) {
tsk = &tsklist[tidx];
tsk->tsk_pid = fork();
if (tsk->tsk_pid != 0)
continue;
tsk->tsk_pid = getpid();
dochild(tsk);
}
for (tidx = 0; tidx < NTASK; ++tidx) {
tsk = &tsklist[tidx];
waitpid(tsk->tsk_pid,NULL,0);
}
#if 1
for (tidx = 0; tidx < NTASK; ++tidx) {
tsk = &tsklist[tidx];
sem_unlink(tsk->tsk_name);
}
#endif
shmdt(sptr);
return 0;
}
这是运行的输出:
Tidx:0 Pid:18563 Seq:0 Counter:1
Tidx:0 Pid:18563 Seq:1 Counter:4
Tidx:0 Pid:18563 Seq:2 Counter:7
Tidx:0 Pid:18563 Seq:3 Counter:10
Tidx:1 Pid:18564 Seq:4 Counter:1
Tidx:1 Pid:18564 Seq:5 Counter:4
Tidx:1 Pid:18564 Seq:6 Counter:7
Tidx:1 Pid:18564 Seq:7 Counter:10
Tidx:2 Pid:18565 Seq:4 Counter:1
Tidx:2 Pid:18565 Seq:9 Counter:4
Tidx:2 Pid:18565 Seq:10 Counter:7
Tidx:2 Pid:18565 Seq:11 Counter:10