Многопоточность. Linux

Проблема такая. Все вроде бы работает, но вот результат выводит только один из потоков, при чем в разнобой, т.е., то один, то другой, то вообще не выводят. Ожидаемый результат - 200 строк из файла (от каждого потока по 100). Вот код:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

char* gettime()
{
struct tm *u;
char *f;
time_t t = time(NULL);
struct timeval  tv;
gettimeofday(&tv, NULL);
double m = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
double mil = ((m/1000) - (int)(m / 1000)) * 1000;
u = localtime(&t);
char s[44];
for (int i = 0; i<40; i++) s[i] = 0;
int length = strftime(s, 40, "%H:%M:%S:", u);
f = (char*)malloc(sizeof(s));
sprintf(f,"%s%d",s,(int)mil);
return f;
}

void * start_thread (void *message)
{
FILE *fin;
char str[22];
printf ("%s (%x):\n", (const char *) message,gettid());
fin = fopen("out.txt","r");
while (fgets(str,sizeof(str),fin)!=NULL)
{
  printf("%s",str);
}
fclose(fin);
return message;
}
int main ()
{
pid_t pid1,pid2;
pthread_t thing1, thing2;
const char *message1 = "Stream 1";
const char *message2 = "Stream 2";
FILE *fout;
pid1 = fork();
  if(pid1>0)
  {
  pid2 = fork();
    if (pid2>0)  //parent
    {
     fout = fopen("out.txt", "w");
     printf("I am the parent process, My actual pid is %d, time is %s\n",(int)getpid(),gettime());
     for (int i = 0; i<100; i++)
     {
       fprintf(fout,"%d %d %s\n",(i+1),(int)getpid(),gettime());
     }
     fclose(fout);
    }
    else  //child2
    {
    wait();
    printf("I am the child2 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing2, NULL, start_thread, (void *) message2);
    pthread_join (thing2, NULL);
    exit(1);
    }
  }

  else   //child1
  {
    wait();
    printf("I am the child1 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing1, NULL, start_thread, (void *) message1);
    pthread_join (thing1, NULL);
    exit(1);
  }
  return 0;
}

Ответы (1 шт):

Автор решения: AlexGlebe

wait , waitpid - ждут только своих сыновей. При запросе ожидания отца возвращается ошибка. Проверяйте ошибки : if(waitpid(..)==-1) и смотрите потом errno.

Можно сначала создать файл, а потом вызывать потоки и их ждать. Если это вас устроит.

// gcc -Wall -Wextra -Wpedantic -std=c11 -lpthread fork2.c -o fork2
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

char* gettime()
{
struct tm *u;
char *f;
time_t t = time(NULL);
struct timeval  tv;
gettimeofday(&tv, NULL);
double m = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
double mil = ((m/1000) - (int)(m / 1000)) * 1000;
u = localtime(&t);
char s[44];
for (int i = 0; i<40; i++) s[i] = 0;
int length = strftime(s, 40, "%H:%M:%S:", u);
f = (char*)malloc(sizeof(s));
sprintf(f,"%s%d",s,(int)mil);
return f;
}

#include <sys/wait.h>

void * start_thread (void *message)
{
FILE *fin;
char str[22];
printf ("%s (%x):\n", (const char *) message,getpid());
fin = fopen("out.txt","r");
while (fgets(str,sizeof(str),fin)!=NULL)
{
  printf("%s",str);
}
fclose(fin);
return message;
}
# include <errno.h>
int main ()
{
pid_t pid1,pid2;
pthread_t thing1, thing2;
const char *message1 = "Stream 1";
const char *message2 = "Stream 2";
FILE *fout;
//parent
    {
     fout = fopen("out.txt", "w");
     printf("I am the parent process, My actual pid is %d, time is %s\n",(int)getpid(),gettime());
     for (int i = 0; i<100; i++)
     {
       fprintf(fout,"%d %d %s\n",(i+1),(int)getpid(),gettime());
     }
     fclose(fout);
    }

  pid1 = fork();
  if(pid1==0)
     //child1
  {
    printf("I am the child1 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing1, NULL, start_thread, (void *) message1);
    pthread_join (thing1, NULL);
    exit(1);
  }

  pid2 = fork();
    if (pid2==0)  
    //child2
    {
    printf("I am the child2 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing2, NULL, start_thread, (void *) message2);
    pthread_join (thing2, NULL);
    exit(1);
    }

    if(waitpid(pid1,0,0)==-1)
      fprintf(stderr,"waitpid(pid1,0,0):%s\n",strerror(errno));
    if(waitpid(pid2,0,0)==-1)
      fprintf(stderr,"waitpid(pid2,0,0):%s\n",strerror(errno));
   
  return 0;
}

Если в логике программы требуется услышать сигнал от родительского процесса, то это можно устроить, создав канал связи pipe.

int fd1  [ 2 ] ;
if ( pipe ( fd1 ) ) {
  fprintf ( stderr  , "pipe ( fd1 ) : %s\n" , strerror ( errno ) ) ;
  return 1 ; }

int fd2  [ 2 ] ;
if ( pipe ( fd2 ) ) {
  fprintf ( stderr  , "pipe ( fd2 ) : %s\n" , strerror ( errno ) ) ;
  return 1 ; }

Родитель будет посылать сигнал так :

char buf [ 1 ] ;
write  ( fd1 [ 1 ] , buf , 1 ) ;
write  ( fd2 [ 1 ] , buf , 1 ) ;

а сыновья читать так :

char buf [ 1 ] ;
read  ( fd2 [ 0 ] , buf , 1 ) ;

Прога с pipe :

// gcc -Wall -Wextra -Wpedantic -std=c11 -lpthread fork3.c -o fork3
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

char* gettime()
{
struct tm *u;
char *f;
time_t t = time(NULL);
struct timeval  tv;
gettimeofday(&tv, NULL);
double m = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
double mil = ((m/1000) - (int)(m / 1000)) * 1000;
u = localtime(&t);
char s[44];
for (int i = 0; i<40; i++) s[i] = 0;
int length = strftime(s, 40, "%H:%M:%S:", u);
f = (char*)malloc(sizeof(s));
sprintf(f,"%s%d",s,(int)mil);
return f;
}

void * start_thread (void *message)
{
FILE *fin;
char str[22];
printf ("%s (%x):\n", (const char *) message,getpid());
fin = fopen("out.txt","r");
while (fgets(str,sizeof(str),fin)!=NULL)
{
  printf("%s",str);
}
fclose(fin);
return message;
}
# include <errno.h>
int main ()
{
pid_t pid1,pid2;
pthread_t thing1, thing2;
const char *message1 = "Stream 1";
const char *message2 = "Stream 2";
FILE *fout;

// создаём каналы для прослушивания сообщений от сыновей
int fd1  [ 2 ] ;
if ( pipe ( fd1 ) ) {
  fprintf ( stderr  , "pipe ( fd1 ) : %s\n" , strerror ( errno ) ) ;
  return 1 ; }

int fd2  [ 2 ] ;
if ( pipe ( fd2 ) ) {
  fprintf ( stderr  , "pipe ( fd2 ) : %s\n" , strerror ( errno ) ) ;
  return 1 ; }

pid1 = fork();
  if(pid1>0)
  {
  pid2 = fork();
    if (pid2>0)  //parent
    {

      // закрываем чтение
      close ( fd1  [ 0 ] ) ;
      close ( fd2  [ 0 ] ) ;

     fout = fopen("out.txt", "w");
     printf("I am the parent process, My actual pid is %d, time is %s\n",(int)getpid(),gettime());
     for (int i = 0; i<100; i++)
     {
       fprintf(fout,"%d %d %s\n",(i+1),(int)getpid(),gettime());
     }
     fclose(fout);

     // пишем сообщения
     char buf [ 1 ] ;
     write  ( fd1 [ 1 ] , buf , 1 ) ;
     write  ( fd2 [ 1 ] , buf , 1 ) ;

    }
    else  //child2
    {
      // закрываем вывод
      close ( fd2  [ 1 ] ) ;
      // читаем сообщение
      char buf [ 1 ] ;
      read  ( fd2 [ 0 ] , buf , 1 ) ;
    
    printf("I am the child2 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing2, NULL, start_thread, (void *) message2);
    pthread_join (thing2, NULL);
    exit(1);
    }
  }

  else   //child1
  {
    // закрываем вывод
    close ( fd1  [ 1 ] ) ;
    // читаем сообщение
    char buf [ 1 ] ;
    read  ( fd1 [ 0 ] , buf , 1 ) ;
    
    printf("I am the child1 process and my pid is %d! Pid of parent is %d, time is %s\n",(int)getpid(),(int)getppid(),gettime());
    pthread_create (&thing1, NULL, start_thread, (void *) message1);
    pthread_join (thing1, NULL);
    exit(1);
  }
  return 0;
}
→ Ссылка