Многопоточность. 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 шт):
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;
}