【发布时间】:2015-06-12 22:37:31
【问题描述】:
我必须在 Linux 上用 C 语言编写程序。它必须有 3 个进程 - 首先从 STDIN 读取,通过 FIFO 将消息发送到第二个进程,第二个进程计算接收到的消息的长度并将结果发送到第三个进程(也通过 FIFO),后者将其显示在 STDOUT 上。我必须使用信号量来同步它。此外,我必须添加信号处理(我正在使用共享内存) - 一个信号结束程序,第二个停止它,第三个恢复。信号可以发送到任何进程。我已经有一些代码,但它不能正常工作。
第一个问题是同步问题 - 正如您通过运行它所看到的,第二个进程收到了第一条消息,但随后它卡住了。第一个和第二个进程正在显示它们的消息,但不是第三个。有非常相似的,所以很混乱。我必须再发送一条消息,然后 P3 显示上一条的长度。
第二个问题是信号 - 发送一个后,我必须按 Enter(对于 SIGUSR)或发送消息(对于 SIGINT)才能提供服务。
任何想法有什么问题吗?我之前发布的内容有一些改进,但它仍然无法正常工作,我没有太多时间来完成它(直到星期一)。我知道这是很多代码,但是如果有人可以分析第二和第三进程的通信,我将非常感激。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/sem.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#define WRITE 1
#define READ 0
#define MEM_ID 1
#define MEM_SIZE 1
#define OK "[ \033[1;32mOK\033[0m ]\n"
#define ERR "[\033[1;31mFAIL\033[0m] "
#define SIGNAL "\033[1;33m\033[5m>> SIGNAL <<\033[0m\n"
#define S1 SIGINT
#define S2 SIGUSR1
#define S3 SIGUSR2
#define S4 SIGCONT
/* union semun - from POSIX specification for semctl() */
/* NB: on Mac OS X, and apparently in defiance of POSIX, <sys/sem.h> declares union semun */
/*
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
*/
/*
union semun
{
int val;
ushort *array;
};
*/
int process1(void);
int process2(void);
int process3(void);
void signal_callback(int signo);
//void signal_handling(int snd, int rcv); // JL
void signal_handling(void); // JL
void sem_down(int semid, int semnum);
void sem_up(int semid, int semnum);
char work = 1, quit = 0;
char inter_snd = 0, inter_rcv = 0;
struct sembuf semstruct;
int sem23, sem12, mem;
char *message;
int res[3];
static const char *fifoname[] = { "1fifo2", "2fifo3" };
static
void main_quit(int n)
{
printf("%s(): signal %d\n", __func__, n); // JL
kill(res[0], S1);
}
int main(void)
{
//union semun arg; // JL
printf("[G] Launching\n");
signal(SIGINT, main_quit);
signal(SIGTERM, main_quit);
// creating FIFO
printf("[G] Creating FIFO... ");
res[0] = mkfifo(fifoname[0], 0644);
res[1] = mkfifo(fifoname[1], 0644);
if ((res[0] == -1) || (res[1] == -1))
{
perror(ERR);
unlink(fifoname[0]);
unlink(fifoname[1]);
return 1;
}
else
printf(OK);
// create two semaphores and set values
printf("[G] Creating semaphores... ");
sem12 = semget(READ, 1, IPC_CREAT | 0644);
sem23 = semget(WRITE, 1, IPC_CREAT | 0644);
if ((sem23 == -1) || (sem12 == -1))
{
perror(ERR);
return 1;
}
else
printf(OK);
printf("[G] Initializing semaphores values... ");
semctl(sem12, 0, SETVAL, 0);
semctl(sem12, 1, SETVAL, 1);
semctl(sem23, 0, SETVAL, 0);
semctl(sem23, 1, SETVAL, 1);
printf(OK);
// creating shared memory
printf("[G] Reserving shared memory... ");
mem = shmget(MEM_ID, MEM_SIZE, IPC_CREAT | 0644);
message = (char *)shmat(mem, 0, 0);
if (mem == -1)
{
perror(ERR);
return 1;
}
else
printf(OK);
if ((res[0] = fork()) == 0)
{
process1();
exit(0);
}
if ((res[1] = fork()) == 0)
{
process2();
exit(0);
}
if ((res[2] = fork()) == 0)
{
process3();
exit(0);
}
printf("[G] Building process tree... ");
if ((res[0] == -1) || (res[1] == -1) || (res[2] == -1))
{
perror(ERR);
return 1;
}
else
{
printf(OK);
printf("[G] P1[pid]: %d, P2[pid]: %d, P3[pid]: %d\n", res[0], res[1], res[2]);
}
wait(NULL);
wait(NULL);
wait(NULL);
printf("[G] Deleting FIFO... ");
res[0] = unlink(fifoname[0]);
res[1] = unlink(fifoname[1]);
if ((res[0] == -1) || (res[1] == -1))
perror(ERR);
else
printf(OK);
printf("[G] Freeing shared memory... ");
res[0] = shmdt((char *)message);
res[1] = shmctl(mem, IPC_RMID, 0);
if ((res[0] == -1) || (res[1] == -1))
perror(ERR);
else
printf(OK);
printf("[G] Deleting semaphores... ");
res[0] = semctl(sem23, 0, IPC_RMID, 0);
res[1] = semctl(sem12, 0, IPC_RMID, 0);
if ((res[0] == -1) || (res[1] == -1))
perror(ERR);
else
printf(OK);
printf("[G] Ending...\n");
return 0;
}
int process1(void)
{
char tab[100];
FILE *fifoh;
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_callback);
fifoh = fopen(fifoname[0], "w");
setbuf(fifoh, NULL);
printf("[P1] Ready.\n");
//while (fgets(tab, sizeof(tab), stdin) > 0) // JL
while (fgets(tab, sizeof(tab), stdin) != 0) // JL
{
if (work)
{
sem_down(sem12, WRITE);
printf("[P1] Sending: %s", tab);
fprintf(fifoh, "%s\n", tab);
sem_up(sem12, READ);
}
//signal_handling(inter_snd, inter_rcv); // JL
signal_handling(); // JL
}
fclose(fifoh);
printf("[P1] Ending...\n");
return 0;
}
int process2(void)
{
char tab[100];
FILE *fifo_in, *fifo_out;
printf("[P2] Ready.\n");
fifo_in = fopen(fifoname[0], "r");
fifo_out = fopen(fifoname[1], "w");
setbuf(fifo_out, NULL);
setbuf(fifo_in, NULL);
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_callback);
do
{
if (work)
{
sem_down(sem12, READ);
fscanf(fifo_in, "%s", (char *)tab);
sem_up(sem12, WRITE);
printf("[P2] Received \"%s\" with length %zu.\n", tab, strlen(tab));
sem_down(sem23, WRITE);
fprintf(fifo_out, "%d\n", (int)strlen(tab));
sem_up(sem23, READ);
}
//signal_handling(inter_snd, inter_rcv); // JL
signal_handling(); // JL
} while (!quit);
fclose(fifo_in);
fclose(fifo_out);
printf("[P2] Ending...\n");
return 0;
}
int process3(void)
{
FILE *fifo_in;
int count;
printf("[P3] Ready.\n");
signal(S1, signal_callback);
signal(S2, signal_callback);
signal(S3, signal_callback);
signal(S4, signal_callback);
fifo_in = fopen(fifoname[1], "r");
setbuf(fifo_in, NULL);
do
{
if (work)
{
sem_down(sem23, READ);
fscanf(fifo_in, "%d\n", (int *)&count);
sem_up(sem23, WRITE);
printf("[P3] Received: %d characters.\n", count);
}
//signal_handling(inter_snd, inter_rcv); // JL
signal_handling(); // JL
} while (!quit);
fclose(fifo_in);
printf("[P3] Ending...\n");
return 0;
}
//void signal_handling(int snd, int rvc)
void signal_handling(void)
{
if (inter_snd > 0)
{
printf("Signal received...\n");
semstruct.sem_op = -3;
semop(sem23, &semstruct, 1);
*message = inter_snd;
inter_snd = 0;
semstruct.sem_op = 3;
semop(sem12, &semstruct, 1);
printf("Sending to other processes\n");
kill(0, S4);
}
if (inter_rcv)
{
inter_rcv = 0;
semstruct.sem_op = -1;
semop(sem12, &semstruct, 1);
switch (*message)
{
case 1:
printf("Quitting...\n");
quit = 1;
break;
case 2:
printf("Stopping...\n");
work = 0;
break;
case 3:
printf("Starting...\n");
work = 1;
break;
default:
printf("There's garbage in memory :/..\n");
}
semstruct.sem_op = 1;
semop(sem23, &semstruct, 1);
}
}
void signal_callback(int signo)
{
printf(SIGNAL);
switch (signo)
{
case S1:
inter_snd = 1;
break;
case S2:
inter_snd = 2;
break;
case S3:
inter_snd = 3;
break;
case S4:
inter_rcv = 1;
break;
}
}
void sem_down(int semid, int semnum)
{
semstruct.sem_flg = 0;
semstruct.sem_num = semnum;
semstruct.sem_op = -1;
do
{
errno = 0;
semop(semid, &semstruct, 1);
} while (errno == EINTR);
}
void sem_up(int semid, int semnum)
{
semstruct.sem_flg = 0;
semstruct.sem_num = semnum;
semstruct.sem_op = 1;
semop(semid, &semstruct, 1);
}
预期行为:
[P3] Ready.
[P2] Ready.
[P1] Ready.
asd
[P1] Sending: asd
[P2] Received "asd" with length 3.
[P3] Received: 3 characters.
as
[P1] Sending: as
[P2] Received "as" with length 2.
[P3] Received: 2 characters.
信号:
应该接收信号并将其发送到所有其他进程。接下来发生的事情在 singnal_handling 中指定。每个进程都应该显示他们的信息(退出/停止/等)。
实际行为:
[P3] Ready.
[P2] Ready.
[P1] Ready.
asd
[P1] Sending: asd
[P2] Received "asd" with length 3.
dd
[P1] Sending: dd
[P2] Received "dd" with length 2.
[P3] Received: 3 characters. //first message
as
[P1] Sending: as
[P2] Received "as" with length 2.
[P3] Received: 2 characters. //second
asd
[P1] Sending: asd
[P2] Received "asd" with length 3.
[P3] Received: 2 characters. // third
有了信号,嗯...我发现在 SIGINT 之后我可以发送消息,按两次回车然后我得到了预期的行为(退出程序)。当我发送另一个信号时,按 enter 也可以:
$ kill -s SIGUSR1 2900
$ kill -s SIGUSR2 2900
给予:
asd
[P1] Sending: asd
[P2] Received "asd" with length 3.
[P3] Received: 3 characters.
Signal received...
Sending to other processes
>> SIGNAL <<
Stopping...
>> SIGNAL <<
>> SIGNAL <<
>> SIGNAL <<
Signal received...
Sending to other processes
>> SIGNAL <<
>> SIGNAL <<
>> SIGNAL <<
Starting...
[P1] Sending:
Starting...
asd
[P1] Sending: asd
[P2] Received "asd" with length 3.
Starting...
[P3] Received: 3 characters.
再说一遍 - 在发送信号后,我必须发送一条消息以便处理它。所以,它有点工作。但是非常非常糟糕。
【问题讨论】:
-
获得帮助的第一步是提供可编译的代码。此代码尝试在
main()内定义函数main_quit() -
它是可编译的。它正在工作,您可以检查是否需要。
-
啊,好的,这是一个 gcc 扩展。 Nvm(虽然由于便携性问题我不会真的这样做)
-
好吧,我想你是对的,所以我添加了一个快速(临时)修复。
-
我刚尝试用gcc在ubuntu linux 14.04上编译,编译的结果是10个警告,其中一些非常关键,比如#include'ing ipc.h时,必须#定义 _SVID_SOURCE 或 #define _XOPEN_SOURCE。并传递一个 size_t(一个 long int),其中应该使用一个 int 和不正确的类型来创建信号量(sem_t),从 fork()返回值(pid_t)。将 res[] 数组用于两个完全不同的目的。
标签: c linux multiprocessing signals semaphore