这是我的程序应该做的:
创建4个子进程:
进程0从STDIN一次读取1个字节,然后将其写入FIFO
进程1从fifo读取这1个字节,并将其值作为HEX写入共享内存
进程2正在从共享内存中读取HEX值并将其写入管道
最后,进程3正在从管道读取并写入STDOUT(在我的情况下:终端)
我无法改变沟通渠道。 FIFO,然后共享内存,然后管道是唯一的选择。
我的问题:当某个文件被定向到stdin时,程序会随机停止(例如:./ program< / dev / urandom)。有时在写完5个HEX值之后,有时在100之后。奇怪的是,当它工作时,在另一个终端我写“pstree -c”有1个主进程有4个子进程(这就是我想要的),但是当我写入“pstree -c”后停止写入(但仍然运行)只有3个子进程。出于某种原因,即使他们都有(1)在其中,1已经消失了。
我想我可能在此处遇到同步问题,但我无法发现它(我已经尝试了好几个小时)。
以下是代码:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#define BUFSIZE 1
#define R 0
#define W 1
// processes ID
pid_t p0, p1, p2, p3;
// FIFO variables
int fifo_fd;
unsigned char bufor[BUFSIZE] = {};
unsigned char bufor1[BUFSIZE] = {};
// Shared memory variables
key_t key;
int shmid;
char * tab;
// zmienne do pipes
int file_des[2];
char bufor_pipe[BUFSIZE*30] = {};
void proces0()
{
ssize_t n;
while(1)
{
fifo_fd = open("/tmp/fifo",O_WRONLY);
if(fifo_fd == -1)
{
perror("blad przy otwieraniu kolejki FIFO w p0\n");
exit(1);
}
n = read(STDIN_FILENO, bufor, BUFSIZE);
if(n<0)
{
perror("read error w p0\n");
exit(1);
}
if(n > 0)
{
if(write(fifo_fd, bufor, n) != n)
{
perror("blad zapisu do kolejki fifo w p0\n");
exit(1);
}
memset(bufor, 0, n); // czyszczenie bufora
}
close(fifo_fd);
}
}
void proces1()
{
ssize_t m, x;
char wartosc_hex[30] = {};
while(1)
{
if(tab[0] == 0)
{
fifo_fd = open("/tmp/fifo", O_RDONLY); // otwiera plik typu fifo do odczytu
if(fifo_fd == -1)
{
perror("blad przy otwieraniu kolejki FIFO w p1\n");
exit(1);
}
m = read(fifo_fd, bufor1, BUFSIZE);
x = m;
if(x < 0)
{
perror("read error p1\n");
exit(1);
}
if(x > 0)
{
// Konwersja na HEX
if(bufor1[0] < 16)
{
if(bufor1[0] == 10) // gdy enter
{
sprintf(wartosc_hex, "0x0%X\n", bufor1[0]);
}
else
{
sprintf(wartosc_hex, "0x0%X ", bufor1[0]);
}
}
else
{
sprintf(wartosc_hex, "0x%X ", bufor1[0]);
}
// poczekaj az pamiec bedzie pusta (gotowa do zapisu)
strcpy(&tab[0], wartosc_hex);
memset(bufor1, 0, sizeof(bufor1)); // czyszczenie bufora
memset(wartosc_hex, 0, sizeof(wartosc_hex)); // przygotowanie tablicy na zapis wartosci hex
x = 0;
}
close(fifo_fd);
}
}
}
void proces2()
{
close(file_des[0]); // zablokuj kanal do odczytu
while(1)
{
if(tab[0] != 0)
{
if(write(file_des[1], tab, strlen(tab)) != strlen(tab))
{
perror("blad write w p2");
exit(1);
}
// wyczysc pamiec dzielona by przyjac kolejny bajt
memset(tab, 0, sizeof(tab));
}
}
}
void proces3()
{
ssize_t n;
close(file_des[1]); // zablokuj kanal do zapisu
while(1)
{
if(tab[0] == 0)
{
if((n = read(file_des[0], bufor_pipe, sizeof(bufor_pipe))) > 0)
{
if(write(STDOUT_FILENO, bufor_pipe, n) != n)
{
perror("write error w proces3()");
exit(1);
}
memset(bufor_pipe, 0, sizeof(bufor_pipe));
}
}
}
}
int main(void)
{
key = 5678;
int status;
// Tworzenie plikow przechowujacych ID procesow
int des_pid[2] = {};
char bufor_proces[50] = {};
mknod("pid0", S_IFREG | 0777, 0);
mknod("pid1", S_IFREG | 0777, 0);
mknod("pid2", S_IFREG | 0777, 0);
mknod("pid3", S_IFREG | 0777, 0);
// Tworzenie semaforow
key_t klucz;
klucz = ftok(".", 'a'); // na podstawie pliku i pojedynczego znaku id wyznacza klucz semafora
if(klucz == -1)
{
perror("blad wyznaczania klucza semafora");
exit(1);
}
semafor = semget(klucz, 1, IPC_CREAT | 0777); // tworzy na podstawie klucza semafor. 1 - ilosc semaforow
if(semafor == -1)
{
perror("blad przy tworzeniu semafora");
exit(1);
}
if(semctl(semafor, 0, SETVAL, 0) == -1) // ustawia poczatkowa wartosc semafora (klucz, numer w zbiorze od 0, polecenie, argument 0/1/2)
{
perror("blad przy ustawianiu wartosci poczatkowej semafora");
exit(1);
}
// Tworzenie lacza nazwanego FIFO
if(access("/tmp/fifo", F_OK) == -1) // sprawdza czy plik istnieje, jesli nie - tworzy go
{
if(mkfifo("/tmp/fifo", 0777) != 0)
{
perror("blad tworzenia FIFO w main");
exit(1);
}
}
// Tworzenie pamieci dzielonej
// Lista pamieci wspoldzielonych, komenda "ipcs"
// usuwanie pamieci wspoldzielonej, komenta "ipcrm -m ID_PAMIECI"
shmid = shmget(key, (BUFSIZE*30), 0666 | IPC_CREAT);
if(shmid == -1)
{
perror("shmget");
exit(1);
}
tab = (char *) shmat(shmid, NULL, 0);
if(tab == (char *)(-1))
{
perror("shmat");
exit(1);
}
memset(tab, 0, (BUFSIZE*30));
// Tworzenie lacza nienazwanego pipe
if(pipe(file_des) == -1)
{
perror("pipe");
exit(1);
}
// Tworzenie procesow potomnych
if(!(p0 = fork()))
{
des_pid[W] = open("pid0", O_WRONLY | O_TRUNC | O_CREAT); // 1 - zapis, 0 - odczyt
sprintf(bufor_proces, "Proces0 ma ID: %d\n", getpid());
if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces))
{
perror("blad przy zapisie pid do pliku w p0");
exit(1);
}
close(des_pid[W]);
proces0();
}
else if(p0 == -1)
{
perror("blad przy p0 fork w main");
exit(1);
}
else
{
if(!(p1 = fork()))
{
des_pid[W] = open("pid1", O_WRONLY | O_TRUNC | O_CREAT); // 1 - zapis, 0 - odczyt
sprintf(bufor_proces, "Proces1 ma ID: %d\n", getpid());
if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces))
{
perror("blad przy zapisie pid do pliku w p1");
exit(1);
}
close(des_pid[W]);
proces1();
}
else if(p1 == -1)
{
perror("blad przy p1 fork w main");
exit(1);
}
else
{
if(!(p2 = fork()))
{
des_pid[W] = open("pid2", O_WRONLY | O_TRUNC | O_CREAT); // 1 - zapis, 0 - odczyt
sprintf(bufor_proces, "Proces2 ma ID: %d\n", getpid());
if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces))
{
perror("blad przy zapisie pid do pliku w p2");
exit(1);
}
close(des_pid[W]);
proces2();
}
else if(p2 == -1)
{
perror("blad przy p2 fork w main");
exit(1);
}
else
{
if(!(p3 = fork()))
{
des_pid[W] = open("pid3", O_WRONLY | O_TRUNC | O_CREAT); // 1 - zapis, 0 - odczyt
sprintf(bufor_proces, "Proces3 ma ID: %d\n", getpid());
if(write(des_pid[W], bufor_proces, sizeof(bufor_proces)) != sizeof(bufor_proces))
{
perror("blad przy zapisie pid do pliku w p3");
exit(1);
}
close(des_pid[W]);
proces3();
}
else if(p3 == -1)
{
perror("blad przy p3 fork w main");
exit(1);
}
else
{
// proces macierzysty
waitpid(p0, &status, 0);
waitpid(p1, &status, 0);
waitpid(p2, &status, 0);
waitpid(p3, &status, 0);
//wait(NULL);
unlink("/tmp/fifo");
shmdt(tab); // odlaczenie pamieci dzielonej
shmctl(shmid, IPC_RMID, NULL); // usuwanie pamieci wspoldzielonej
printf("\nKONIEC PROGRAMU\n");
}
}
}
}
exit(0);
}
使用“strace ./projekt_wlasciwy&lt; / dev / urandom”之后 我有这样的事情:
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e2e728) = 26916
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e2e728) = 26917
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e2e728) = 26918
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb7e2e728) = 26919
waitpid(26916, 0xAA 0xC1 0x84 0x9C 0x4E 0x0D 0x54 0xB2 0xE7 0x19 0x22 0xA0 0x2E 0xF0 0x1C 0xC4 0xDF 0x21 0xA2 0xB4 0x3B 0xEE [{WIFSIGNALED(s) && WTERMSIG(s) == SIGPIPE}], 0) = 26916
--- SIGCHLD (Child exited) @ 0 (0) ---
waitpid(26917, 0x40 0xbfb083a8, 0) = ? ERESTARTSYS (To be restarted)
--- SIGWINCH (Window changed) @ 0 (0) ---
waitpid(26917, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGTERM}], 0) = 26917
--- SIGTERM (Terminated) @ 0 (0) ---
+++ killed by SIGTERM +++
答案 0 :(得分:2)
代码中存在一些与信号量相关的错误。您的代码中有一个reader(process2)和一个writer(process1)。
他们需要拥有对共享内存的独占访问权限,但未正确完成。您正在使用
semctl(semafor, 0, SETVAL, 0) == -1
似乎这是不正确的。你试图为信号量设置一些值,所以pl。在这种情况下检查第四个参数。 PL。从链接http://pubs.opengroup.org/onlinepubs/7908799/xsh/semctl.html
中读取在共享内存中执行某些操作之前,您还必须检查process1和process2中的信号量值。那些行动在哪里?你需要使用缺少的semop。 PL。阅读链接http://pubs.opengroup.org/onlinepubs/7908799/xsh/semop.html
答案 1 :(得分:0)
您的代码中可能存在一个错误,导致其中一个孩子崩溃。我建议添加一些调试输出(将其写入控制台或日志文件),这样您就可以看到有什么数据输入和输出结果。
我也有点担心输出。 ERESTARTSYS
表示可以重新启动系统调用(=再试一次)。不确定它来自哪里。
同样SIGTERM
表示有人杀了这个进程。但那可能是strace
告诉你你停止了它。如果它是其中一个孩子的输出,那么就有人杀了你的过程。