LINUX.ORG.RU

Потоки

 ,


0

2

Не так давно создавал тут тему. Про «Родительский процесс создает n дочерних процессов и передает им поочередно числа .Дочерний процесс при создании принимает имя файла. При работе дочерний процесс получает числа от родительского процесса и пишет их в файл.»

С чем-то помогли, с чем-то разобрался сам. Но в фаил почему-то не пишется. Предварительно создал Foo_N(N=1,2,3...).txt Что не правильно?

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

int main (void) 
{
	int status, n, q=0, result;
	pid_t pid; 
	size_t i;
        const size_t MAX_FILE_NAME = 100;
  	char file_name[MAX_FILE_NAME],somedata[10];
	int data_processed, filepipes[2];
	int PIP1[2];

	printf("Сколько дочерних процессов создать?\n");
	scanf("%d", &n);
	pipe(PIP1);
	// 0 read
	// 1 write 

	printf("Enter string\n");
	for(q=1;q<=n;q++){	
		snprintf(file_name, MAX_FILE_NAME, "Foo_%d.txt", q);
	
		if ((pid = fork()) == -1){
			exit(-1);}
	

		if ((pid=fork()) != 0) {
		//PARENT
			close(PIP1[0]);//выход не нужен
			dup2(PIP1[1], 0);//на вход stdin
			printf("I send file name: %s\n", file_name);
			waitpid(-1, &status, 0); 
		} 
		else {
		//CHILD
			close(PIP1[1]);
			dup2(PIP[0],*file_name);
	 		printf("I recv file name: %s\n", file_name);
			break;		
		}
	}
}



Последнее исправление: timas-cs (всего исправлений: 1)

dup2(PIP[0],*file_name);

this

trex6 ★★★★★
()
 			dup2(PIP[0],*file_name);
 

классно наверное указатель на строку вместо дескриптора файла пихать. ты его хоть открыт бы.

lberserq
()

if ((pid = fork()) == -1){
if ((pid=fork()) != 0) {

А два форка друг за другом в данном случае нормально?

andreyu ★★★★★
()

Исправил, но теперь не считывает с stdin в //Parent

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main (void) 
{
	int status, n, q=0, result, fd;
	pid_t pid; 
	size_t i;
        const size_t MAX_FILE_NAME = 100;
  	char file_name[MAX_FILE_NAME],somedata[10];
	int data_processed, filepipes[2];
	int PIP1[2];

	printf("Сколько дочерних процессов создать?\n");
	scanf("%d", &n);
	pipe(PIP1);
	// 0 read
	// 1 write 

	printf("Enter string\n");
	for(q=1;q<=n;q++){	
		snprintf(file_name, MAX_FILE_NAME, "Foo_%d.txt", q);

		if ((pid=fork()) != 0) {
		//PARENT
			close(PIP1[0]);//выход не нужен
			dup2(PIP1[1], 0);//на вход stdin
			printf("I send file name: %s\n", file_name);
			waitpid(-1, &status, 0); 
		} 
		else {
		//CHILD
			close(PIP1[1]);
		fd = open(file_name, O_WRONLY | O_CREAT, 0666);
		if( fd == -1){
        	printf("File open failed!\n");
        	exit(1);
    		}
			dup2(PIP1[0],fd);
			printf("I recv file name: %s\n", file_name);
			break;		
		}
	}
}

timas-cs
() автор топика
Ответ на: комментарий от lberserq

Тогда не ясно, как связать вход в pipe и stdin

dup2(PIP1[1], 0);


я указал дескриптор stdin'a (0).
Может нужно его отдельно объявить, как FILE* ?
timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Тогда не ясно,

Интересно, а у вас man 2 pipe не даёт нормального примера использования? Там очень хороший пример, он вас почти удовлетворит для вашей задачи и с него и надо начинать.

vodz ★★★★★
()

Окей, понял, а если из родительского процесса нужно передать n символов по одному, а потом записать в файл то пайпы закрывать не нужно? И в чем проблема при записи в файл


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#include <sys/wait.h>

int main (void) 
{
	    char buf;

	int status, n, q=0, result, fd,g;
	pid_t pid; 
	size_t i;
        const size_t MAX_FILE_NAME = 100;
  	char file_name[MAX_FILE_NAME],somedata[10],c[2];
	int data_processed, filepipes[2];
	int PIP1[2];


	printf("Сколько дочерних процессов создать?\n");
	scanf("%d", &n);
	pipe(PIP1);
	// 0 read
	// 1 write 

	for(q=1;q<=n;q++){	
		snprintf(file_name, MAX_FILE_NAME, "Foo_%d.txt", q);

		if ((pid=fork()) != 0) {
			//PARENT
			//close(PIP1[0]);
			printf("Длинна последовательности:\n");
			scanf("%d", &g);

			for(i=0;i<g;i++){			
				printf("Введите символ\n");
				scanf("%s", c);
				write(PIP1[1], c, strlen(c));
				printf("I send file name: %s\n", file_name);
				//close(PIP1[1]);
				waitpid(-1, &status, 0); 
			}
		} 
		else {
		//CHILD
		//close(PIP1[1]);	
		fd = open(file_name, O_WRONLY | O_CREAT, 0666);
		if( fd == -1){
        		printf("File open failed!\n");
        		exit(1);
    		}
			
			while (read(PIP1[0], &buf, 1) > 0){
			write(fd, &buf, 1);
			printf("I recv file name: %s\n", file_name);
			//close(PIP1[0]);
			break;	}	
		}
	}
}

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Ну нельзя так. У каждого сына должен быть свой pipe. Начните с одного сына:

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

int main (void)
{
        int fd;
        pid_t pid;
        ssize_t r;
        char *file_name;
        char inbuf[BUFSIZ];
        int PIP1[2];

        pipe(PIP1);
        fd = snprintf(NULL, 0, "Foo_%d.txt", 1);
        file_name = alloca(fd + 1);
        fd = snprintf(file_name, fd, "Foo_%d.txt", 1);

        if ((pid=fork()) != 0) {
                //PARENT
                close(PIP1[0]);
                printf("Введите посылку для передачи: ");
                while(fgets(inbuf, sizeof(inbuf), stdin) != NULL) {
                        char *p = strchr(inbuf, '\n');
                        write(PIP1[1], inbuf, strlen(inbuf));
                        if(p != NULL)
                                break;
                }
                close(PIP1[1]);
                while(waitpid(pid, NULL, 0) < 0)
                        ;
        } else {
                //CHILD
                close(PIP1[1]);
                fd = open(file_name, O_WRONLY | O_CREAT, 0666);
                if( fd == -1) {
                        fprintf(stderr, "File '%s' create failed!\n", file_name);
                        return 1;
                }


                printf("I receive: ");
                while ((r = read(PIP1[0], inbuf, sizeof(inbuf))) > 0) {
                        write(fd, inbuf, r);
                        printf("%s", inbuf);
                }
        }
        return 0;
}

vodz ★★★★★
()

Потоки — это pthreads, а у тебя процессы, т.к. fork!

anonymous
()
Ответ на: комментарий от vodz

Понял, что для каждого сына свой pipe, но что делать c n сыновьями до сих пор не вьезжаю. Нужно как-то объявлять pipe внутри цикла, в котором создаем потомков?

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Сдались тебе эти пайпы! Ты что, больше никаких IPC не знаешь?

anonymous
()
Ответ на: комментарий от vodz

Как-то так, только почему-то циклы на 1 раз больше положенного работают

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

int main (void)
{
        int fd,n,i,j,m;
        pid_t pid;
        ssize_t r;
        char *file_name;
        char inbuf[BUFSIZ];
	char g;
	
	
	printf("Сколько дочерних процессов создать?\n");
	fgets(inbuf, sizeof(inbuf), stdin);
	n=atoi(inbuf);
	printf("N=%d\n",n);
	
	for(i=0;i<n;i++){
	int PIP1[2];
        pipe(PIP1);
        fd = snprintf(NULL, 0, "Foo_%d.txt", i);
        file_name = alloca(fd + i);
        fd = snprintf(file_name, fd, "Foo_%d.txt", i);

        if ((pid=fork()) != 0) {
                //PARENT
                close(PIP1[0]);
		printf("Длинна последовательности:\n");
		fgets(inbuf, sizeof(inbuf), stdin);
		m=atoi(inbuf);
		printf("M=%d\n",m);
		
		for(j=0;j<m;j++){
                printf("Введите посылку для передачи: ");
                while(fgets(inbuf, sizeof(inbuf), stdin) != NULL) {
                        char *p = strchr(inbuf, '\n');
                        write(PIP1[1], inbuf, strlen(inbuf));
                        if(p != NULL)
                                break;}
                }
                close(PIP1[1]);
                while(waitpid(pid, NULL, 0) < 0)
                        ;
        } else {
                //CHILD
                close(PIP1[1]);
                fd = open(file_name, O_WRONLY | O_CREAT, 0666);
                if( fd == -1) {
                        fprintf(stderr, "File '%s' create failed!\n", file_name);
                        return 1;
                }


                printf("I receive: ");
                while ((r = read(PIP1[0], inbuf, sizeof(inbuf))) > 0) {
                        write(fd, inbuf, r);
                        printf("%s", inbuf);
                }}
        }
        return 0;
}

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

При таком ручном вводе данных у вас вряд ли получится показать параллельность процессов. Необходим быстрый генератор данных, который отправлял порции то в один, то в другой дочерний процесс. Тогда у вас pipefd надо будет генерировать правильно:

        printf ("Сколько дочерних процессов создать ");
        fgets (inbuf, sizeof (inbuf), stdin);
        n = atoi (inbuf);
        printf ("N=%d\n", n);
        p_pipefd = malloc(n * 2 * sizeof(int));

        for (i = 0; i < n; i++) {
                int *PIP1 = p_pipefd + i * 2;

vodz ★★★★★
()
Ответ на: комментарий от vodz

Наверное я Вам уже надоел, но дело в том, что это моя первая программа под unix. И многие вещи достаточно сложны.Добавил генератор, но ничего не изменилось, что с ним делать?

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

int main (void)
{
        int fd,n,i,j,m;
        pid_t pid;
        ssize_t r;
        char *file_name;
        char inbuf[BUFSIZ];
	char g;
	int *p_pipefd;
	
	printf ("Сколько дочерних процессов создать ");
        fgets (inbuf, sizeof (inbuf), stdin);
        n = atoi (inbuf);
        printf ("N=%d\n", n);
        p_pipefd = malloc(n * 2 * sizeof(int));

        for (i = 0; i < n; i++) {
                int *PIP1 = p_pipefd + i * 2;
        pipe(PIP1);

	fd = snprintf(NULL, 0, "Foo_%d.txt", i);
        file_name = alloca(fd + i);
        fd = snprintf(file_name, fd, "Foo_%d.txt", i);



        if ((pid=fork()) != 0) {
                //PARENT
                close(PIP1[0]);
		printf("Длинна последовательности:\n");
		fgets(inbuf, sizeof(inbuf), stdin);
		m=atoi(inbuf);
		printf("M=%d\n",m);
		
		for(j=0;j<m;j++){
                printf("Введите посылку для передачи: ");
                while(fgets(inbuf, sizeof(inbuf), stdin) != NULL) {
                        char *p = strchr(inbuf, '\n');
                        write(PIP1[1], inbuf, strlen(inbuf));
                        if(p != NULL)
                                break;}
                }
                close(PIP1[1]);
                while(waitpid(pid, NULL, 0) < 0)
                        ;
        } else {
                //CHILD
                close(PIP1[1]);
                fd = open(file_name, O_WRONLY | O_CREAT, 0666);
                if( fd == -1) {
                        fprintf(stderr, "File '%s' create failed!\n", file_name);
                        return 1;
                }


                printf("I receive: ");
                while ((r = read(PIP1[0], inbuf, sizeof(inbuf))) > 0) {
                        write(fd, inbuf, r);
                        printf("%s", inbuf);
                }}
        }
        return 0;
}

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Добавил генератор, но ничего не изменилось, что с ним делать?

Так у вас ничего и не изменилось. Никакого генератора данных я не увидел. У вас как и было: создать межпроцессную трубу, дочерний процесс, дождаться ввода данных, отправить в эту трубу и ожидать завершения этого одного конкретного процесса-сына.

vodz ★★★★★
()
Ответ на: комментарий от vodz

А без генератора возможно исправить проблему с циклами? Если нет, то как правильно организовать его? waitpid получается не нужен

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

А без генератора возможно исправить проблему с циклами?

Сыновьям то что делать? Сейчас они ожидают данные и закрытия входа для выхода из своего цикла записи в файл.

Надо написать генератор что-то типа такого: случайно генерируем число от 0 до N - номер сына. Потом случайно генерируем посылку. Можно всё это записать в отладочный файл.

waitpid получается не нужен

Когда несколько своих сыновей могут завершиться в любое время, то wait()-ом ожидать не получится, надо обрабатывать сигналы SIGCHLD. Но после закрытия всех труб на запись можно ожидать завершения всех оставшихся в живых сыновей в режиме как вы изначально использовали - ожидать завершения любого сына, проверять есть ли ещё и снова ожидать.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Вроде нашел нужную функцию-обработчик и написал совсем простой генератор, числа генерируются и даже записываются в файлы, но программа останавливается на

if((pid = waitpid(-1, &status, 0)) < 0){
       	 	/* Если возникла ошибка – сообщаем о ней и 
        	продолжаем работу */ 
        	printf("Some error on waitpid errno = %d\n",errno);


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

int main (void)
{
        int fd,n,i,j,m,ran,son,status;
        pid_t pid;
        ssize_t r;
        char *file_name;
	char g;
	int *p_pipefd;
	char inbuf[BUFSIZ];


	/*Обработчик сигнала SIGCHLD */ 
	void my_handler(int nsig){
    	int status, errno;
    	pid_t pid;
    	/* Опрашиваем статус завершившегося процесса и 
   	 одновременно узнаем его идентификатор */ 
   		if((pid = waitpid(-1, &status, 0)) < 0){
       	 	/* Если возникла ошибка – сообщаем о ней и 
        	продолжаем работу */ 
        	printf("Some error on waitpid errno = %d\n",errno);
    		} else {
        	/* Иначе анализируем статус завершившегося процесса */ 
       			 if ((status & 0xff) == 0) {
            		/* Процесс завершился с явным или неявным 
			вызовом функции exit() */ 
        		printf("Process %d was exited with status %d\n", pid, status >> 8);
        		} else if ((status & 0xff00) == 0){
            		/* Процесс был завершен с помощью сигнала */ 
            		printf("Process %d killed by signal %d %s\n", 
            		pid, status &0x7f,(status & 0x80) ? "with core file" : "without core file");
        }
    		}
			}



	printf ("Сколько дочерних процессов создать ");
        fgets (inbuf, sizeof (inbuf), stdin);
        n = atoi (inbuf);
        printf ("N=%d\n", n);
	printf("Длинна последовательности:\n");
	fgets(inbuf, sizeof(inbuf), stdin);
	m=atoi(inbuf);
	printf("M=%d\n",m);


	
	p_pipefd = malloc(n * 2 * sizeof(int));
	for (i = 1; i <= n; i++) {
        	int *PIP1 = p_pipefd + i * 2;
        	pipe(PIP1);

		fd = snprintf(NULL, 0, "Foo_%d.txt", i);
       		file_name = alloca(fd + 1);
       		fd = snprintf(file_name, fd, "Foo_%d.txt", i);

		(void) signal(SIGCHLD, my_handler);

       		if ((pid=fork()) != 0) {
        	        //PARENT
        	        close(PIP1[0]);
			for(j=1;j<=m;j++){
				//Generator
        			ran=1+rand()%m;  
				printf ("RandomInt=%d\n", ran);
				son=1+rand()%n;
				printf("To son № %d\n", son);
				//
				sprintf(inbuf, "%d", ran);
        	                write(PIP1[1], inbuf, strlen(inbuf));
        	        }
        	        close(PIP1[1]);
        	        while(waitpid(-1, &status, 0));

        	} else {
        	        //CHILD
        	        close(PIP1[1]);
        	        fd = open(file_name, O_WRONLY | O_CREAT, 0666);
        	        if( fd == -1) {
        	                fprintf(stderr, "File '%s' create failed!\n", file_name);
        	                return 1;
        	        }


        	        printf("I receive: ");
        	        while ((r = read(PIP1[0], inbuf, sizeof(inbuf))) > 0) {
        	                write(fd, inbuf, r);
        	                printf("%s", inbuf);
        	        }}
        	}
        	return 0;
}
timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Таки и пришлось за вас всё писать:

#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>

/* Обработчик сигнала SIGCHLD */
static int *childs;
static int n;

static void
my_handler (int nsig)
{
  int i;

  for(;;) {
	int pid = waitpid (-1, NULL, nsig == 0 ? 0 : WNOHANG);
        if(pid < 0) {
                if(errno == EINTR)
                        continue;
                pid = 0;
        }
	if(pid == 0)
		return;
	for(i = 0; i < n; i++)
		if(childs[i] == pid) {
			childs[i] = 0;
                       if(nsig)
                                return;
		}
  }
}

static int get_int(const char *prompt)
{
	long r;
	char *e;
	char inbuf[128];

	for(;;) {
		printf ("%s ", prompt);
		if(fgets (inbuf, sizeof (inbuf), stdin) == NULL)
			exit(0);
		errno = 0;
		r = strtol(inbuf, &e, 10);
		if(e == inbuf || errno != 0 || *e != '\n' || r <= 0 || r > INT_MAX) {
			fprintf(stderr, "Strange number '%s'\n", inbuf);
		} else {
			return r;
		}
	}
}

#define MSG_LENGHT 60
static void fill_msg(char *buf)
{
	int i;

	for(i = 0; i < MSG_LENGHT; i++) {
		buf[i] = '!' + (rand() % ('~' - ' '));
	}
	buf[i] = '\n';
}

int
main (void)
{
  int fd, i, m;
  pid_t pid;
  ssize_t r;
  char *file_name;
  int *p_pipefd;
  int *PIP1;
  char inbuf[MSG_LENGHT + 2];

  n = get_int ("Сколько дочерних процессов создать");
  m = get_int ("Количество циклов * количество процессов");

  p_pipefd = malloc (n * 3 * sizeof (int));
  childs = p_pipefd + n * 2;
  for (i = 0; i < n; i++) {
	PIP1 = p_pipefd + i * 2;
	pipe (PIP1);

	fd = snprintf (NULL, 0, "Foo_%d.txt", i + 1);
	file_name = alloca (fd + 1);
	snprintf (file_name, fd + 1, "Foo_%d.txt", i + 1);

	(void) signal (SIGCHLD, my_handler);

	if ((pid = fork ()) != 0) {
	  //PARENT
	  if(pid < 0) {
		fprintf(stderr, "fork(): %s\n", strerror(errno));
		return 1;
	  }
	  close (PIP1[0]);
	  childs[i] = pid;

	} else {
	  //CHILD
	  int my_pid = getpid();

	  close (PIP1[1]);
	  fd = open (file_name, O_WRONLY | O_CREAT, 0666);
	  if (fd == -1) {
		fprintf (stderr, "File '%s' create failed!\n", file_name);
		return 1;
	  }

	  while ((r = read (PIP1[0], inbuf, MSG_LENGHT + 1)) > 0) {
		write (fd, inbuf, r);
		printf ("I (%d) receive: %s", my_pid, inbuf);
	  }
	  printf ("I (%d) exited\n", my_pid);
	  return 0;
	}
  }

  for (i = 0; i < (n * m); i++) {
	fd = rand () % n;
	fill_msg(inbuf);
	printf("Parent send to %d pid\n", childs[fd]);
	write (p_pipefd[fd * 2 + 1], inbuf, MSG_LENGHT + 1);
  }
  for (i = 0; i < n; i++)
	close (p_pipefd[i * 2 + 1]);

  my_handler(0);
  return 0;
}
$ ./a.out
Сколько дочерних процессов создать 3
Количество циклов * количество процессов 4
Parent send to 6624 pid
Parent send to 6623 pid
Parent send to 6623 pid
Parent send to 6624 pid
Parent send to 6624 pid
Parent send to 6624 pid
I (6623) receive: A07$Q:vFEr_`!f%w>/$U+%59T`7z+kwe6/%gczHCm)>**C<aQY8uwf0LaFa(
Parent send to 6623 pid
Parent send to 6624 pid
Parent send to 6623 pid
I (6623) receive: Zlb$,d"BGDJibmr@+op}("vm1CPq&qXyxU8&::G{wpeZyY5%c@#jB4rRW]^v
Parent send to 6623 pid
Parent send to 6623 pid
I (6623) receive: MWdS1tD2O)^mgLY2<^DUnz+;B)_3o=4=/3,?)OkqWJyZvT'M3d=#`GW#j85Z
Parent send to 6625 pid
I (6623) receive: 8>cj7;sb4?SjWIJ(Lb$on!pN-Acg>}Kp=/umcikw)Y|y=H#hE@rN@}7gZyiw
I (6623) receive: O$jwxr[|xmAS';oNWs.v"vR!.TZ)>lVlpAd%NZ=HI]zO3&8jx_{zVh6d=+(t
I (6623) receive: ]{#9zB"V^I:V^$h~Umw5j.km]j,gq;yi8{=3X>$7#=lzZpy0^._IUeR4P]6\
I (6624) receive: %b82j1Sll+2MlR57e3Erubv5Qo2dV<u[9H($Yto`~<.'*]=*o|{"_s6K}GJT
I (6624) receive: 8,IlCNB\0>o;$J5v_SZ~p_[%SIuK((zY3^aVG$MV[=,x#[p{Ie6T`qYN;ix\
I (6625) receive: 0`JG8]~ozQq9Xm.I#>)0|ke|>xM6/DIY%.!V&:F"jS:D[G(]~Jm77S4nfz@0
I (6624) receive: /7?lwt46]%pyKi7't3iuc?VU3?+{8f)G8HN0Wb_5"P0LU`ldsWZW1KGCiQ?=
I (6625) exited
I (6624) receive: b}j+L5aI0vKyA2O":O0,D"<oH^s48K"yI'?1U"Yd3?_SQInjw:u=;LG}+UL\
I (6624) receive: b2|u=<9'B+xl%S}rsKAXg]9I5V4L&m;h!8xWnL^1VW8tE6h9zD,b"E-66Z|;
I (6624) exited
I (6623) exited
Случайное завершение процессов напишите сами.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Спасибо большое, за всю помощь. Буду разбираться.

timas-cs
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.