C procesy, sygnały, pipe

0

Mam następujący problem przy pisaniu wieloprocesowego programu, tworzę nowy wątek chce wczytać w nim ciąg tekstowy i przesłać go pipem do procesu głównego,
w procesie głównym chciałbym odczytać ciąg i go wyświetlić, następnie chciałbym znów zrobić coś w procesie potomnym.
Problem w tym, że wykonuje się to szybciej niż proces głównym, a chciałbym ,żeby działało to tak :
wczytanie danych w procesie potomnym -> odczyt w procesie głównym ->wyświetlenie tekstu w procesie potomnym

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>


int main(int argc, char const *argv[])
{
    int p1;
    int first_pipe[2];

    if(pipe(first_pipe) == -1 )
        printf("Pipe error\n");

    p1 = fork();

    if(p1 > 0) 
        {
           
         printf("PM: %d P1: %d\n",getpid(),p1);
         wait(NULL);

        }

    if(p1 == 0)
    {
        char str[50];
        printf("PP1:Podaj tekst: ");
        fgets(str,50,stdin);
        str[strlen(str) - 1] = '\0';

        int n = strlen(str) + 1;
        write(first_pipe[1],&n,sizeof(n));

        write(first_pipe[1],str,sizeof(char) * n)
       }

       if(p1 > 0)
    {
        
        char str[50];
        int n;

        read(first_pipe[0], &n, sizeof(n));
        read(first_pipe[0], str,sizeof(char)*n);
        printf("%s\n",str);   
    }   

    if(p1 == 0)
    	printf("Hello world\n");

3

wait czeka na zamknięcie procesu potomnego.
https://www.geeksforgeeks.org/wait-system-call-c/

0

Jak w takim razie rozwiązać to bez używania wait ?

1

Ogarnąłem to, wysyłając sygnał SIGSTOP w procesie potomnym do samego siebie, a potem w procesie nadrzędnym SIGCONT

1

Zaraz zaraz, po kolei... Jeśli dobrze rozumiem, to wielkiej filozofii tu nie ma. Weźmy najprostszy przykład z jednym komunikatem do przesłania:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>

#define BUFFER_SIZE 512

void readDataFromStd(char buffer[]) {
	memset(buffer, 0, BUFFER_SIZE + 1);

	printf(">>> ");
	scanf("%s", buffer);
}

int main() {
	char buffer[BUFFER_SIZE + 1];
	int pipefd[2];
	ssize_t bytesCount = 0;
	pid_t pid;
	printf("Hello, World!\n");

	pipe(pipefd);
	pid = fork();

	if (pid < 0) {
		perror("Can't fork! Quitting...");
		return 1;
	}

	if (pid == 0) {
		close(pipefd[0]);
		readDataFromStd(buffer);

		bytesCount = write(pipefd[1], buffer, BUFFER_SIZE);
		close(pipefd[1]);
		printf("Child sent %ld bytes\n", bytesCount);
		_exit(EXIT_SUCCESS);
	} else {
		close(pipefd[1]);
		memset(buffer, 0, BUFFER_SIZE + 1);

		bytesCount = read(pipefd[0], buffer, BUFFER_SIZE);
		printf("Parent received %ld bytes:\n%s\n", bytesCount, buffer);

		close(pipefd[0]);
		wait(NULL);
		_exit(EXIT_SUCCESS);
	}
}


W tym kodzie funkcja write działa w trybie blokującym, więc poczeka na na proces piszący. A zatem:

  • oba procesy startują,
  • proces czytający dochodzi do funkcji write i czeka na dane,
  • w tym samym momencie proces piszący prosi o wpisanie danych i chwilę później pisze do rury,
  • proces czytający może ruszyć, więc czyta,
  • proces piszący nie ma nic do roboty i kończy się,
  • proces czytający sprawdza czy są dzieci do czekania na nie (funkcją wait) i - ponieważ owych dzieci nie ma - wychodzi.

Jeśli zatem dodamy kod jeszcze jeden etap komunikacji, też to zadziała:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>

#define BUFFER_SIZE 512

void readDataFromStd(char buffer[]) {
	memset(buffer, 0, BUFFER_SIZE + 1);

	printf(">>> ");
	scanf("%s", buffer);
}

int main() {
	char buffer[BUFFER_SIZE + 1];
	int pipefd[2];
	ssize_t bytesCount = 0;
	pid_t pid;
	printf("Hello, World!\n");

	pipe(pipefd);
	pid = fork();

	if (pid < 0) {
		perror("Can't fork! Quitting...");
		return 1;
	}

	if (pid == 0) {
		close(pipefd[0]);
		readDataFromStd(buffer);
		bytesCount = write(pipefd[1], buffer, BUFFER_SIZE);
		printf("Child sent %ld bytes\n", bytesCount);
		//-----------------------------------------------------------------------------
		readDataFromStd(buffer);
		bytesCount = write(pipefd[1], buffer, BUFFER_SIZE);
		//-----------------------------------------------------------------------------
		close(pipefd[1]);
		printf("Child sent %ld bytes\n", bytesCount);
		_exit(EXIT_SUCCESS);
	} else {
		close(pipefd[1]);
		memset(buffer, 0, BUFFER_SIZE + 1);

		bytesCount = read(pipefd[0], buffer, BUFFER_SIZE);
		printf("Parent received %ld bytes:\n%s\n", bytesCount, buffer);

		//-----------------------------------------------------------------------------
		memset(buffer, 0, BUFFER_SIZE + 1);
		bytesCount = read(pipefd[0], buffer, BUFFER_SIZE);
		printf("Parent received %ld bytes:\n%s\n", bytesCount, buffer);
		//-----------------------------------------------------------------------------

		close(pipefd[0]);
		wait(NULL);
		_exit(EXIT_SUCCESS);
	}
}

Druga sprawa: zabawa z strlen. Nie wiem jaki był cel. Jeśli ustalenie długości, to są inne sposoby. Przed użyciem zmiennej typu char[]czyścimy ją zerami. Ponieważ tekst w C jest zakończony zerem, taki ciąg znaków ma zerową długość. Jeśli do tablicy znaków o długości 512 wpiszemy 10 znaków, to cała reszta dalej jest wyzerowana. Jakakolwiek funkcja szukająca znaku 0 znajdzie go na jedenastym miejscu i dalej przestanie szukać. Poza tym, jeśli chcemy mieć pewność, że funkcja scanf wczyta maksymalnie tyle, ile chcemy, piszemy:

char buffer[100];
scanf("%10s", buffer);

W tym przypadku %10s znaczy, że oczekujemy dziesięciu znaków.
To, co napisałem w tym kodzie, powinno wystarczyć w prostych apkach. W poważnych programach można się pokusić o to, żeby drugi proces nie pisał nic na konsolę, jeśli pierwszy nie skończy czytać. W tym momencie mam coś takiego:

Hello, World!
>>> 123
Child sent 10 bytes
>>> Parent received 10 bytes:
123
567
Child sent 10 bytes
Parent received 10 bytes:
567

Trochę tekst się pomieszał, ale w tym przypadku to nic. W tym momencie to nie boli a zabawa w synchronizację jest ciężka.

1 użytkowników online, w tym zalogowanych: 0, gości: 1