1

这是我的程序应该做的事情:

创建4个子进程:

进程 0 一次从 STDIN 读取 1 个字节,然后将其写入 FIFO

进程 1 正在从 fifo 读取这 1 个字节并将其值作为 HEX 写入共享内存

进程 2 正在从共享内存中读取 HEX 值并将其写入管道

最后进程3正在从管道读取并写入STDOUT(在我的例子中:终端)

我无法改变沟通渠道。FIFO,然后是共享内存,然后是管道是唯一的选择。

我的问题:当某些文件被定向到标准输入时,程序会随机停止(例如:./program < /dev/urandom)。有时在写 5 个 HEX 值之后,有时在 100 之后。奇怪的是,当它工作时,在另一个终端中我写“pstree -c”有 1 个主进程和 4 个子进程(这是我想要的),但是当我在停止写入(但仍在运行)后写入“pstree -c”,只有 3 个子进程。出于某种原因 1 消失了,即使它们都有 while(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 < /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 +++
4

2 回答 2

2

代码中有一些与信号量相关的错误。您的代码中有一个 reader(process2) 和一个 writer(process1)。

他们需要拥有对共享内存的独占访问权限,但这是不正确的。您正在使用

semctl(semafor, 0, SETVAL, 0) == -1

似乎这是不正确的。您正在尝试为信号量设置一些值,所以请。在这种情况下检查第四个参数。PL。从链接http://pubs.opengroup.org/onlinepubs/7908799/xsh/semctl.html阅读

此外,您还应该检查 process1 和 process2 中的信号量值,然后才能在共享内存中执行某些操作。这些操作在哪里?您需要使用缺少的 semop。PL。阅读链接http://pubs.opengroup.org/onlinepubs/7908799/xsh/semop.html

于 2012-09-03T18:04:56.623 回答
0

您的代码中可能存在一个错误,导致其中一个孩子崩溃。我建议添加一些调试输出(将其写入控制台或日志文件),以便您可以查看输入的数据和输出的数据。

我也有点担心输出。ERESTARTSYS表示有一个可以重新启动的系统调用(= 再试一次)。不知道那是从哪里来的。

SIGTERM意味着有人杀死了这个过程。但这可能会strace告诉你你停止了它。如果它是其中一个孩子的输出,那么有人杀死了你的进程。

于 2012-09-03T16:12:05.487 回答