Witam
Background:
Jeżeli otworzymy file deskryptor przed forkiem to wtedy po forku po stronie kernela w file table entry (FTE) referencja do file deskryptora zostanie zinkrementowana czyli będzie równa 2, co oznacza tyle, że offset na pliku będzie współdzielony pomiędzy procesami. Jeżeli dasz write("xx") w child procesie a w macierzystym write("yy") (przy założeniu że macierzysty czeka na childa) to w sumie będziesz miał w pliku zapisane "xxyy". Jakby były różne file deskryptory to byśmy mieli "yy".
Jestem jednak zaskoczony że wywołanie 2 razy pod rząd w przypadku wyżej w obrębie jednego procesu close() za drugim razem fejluje. Ale jak już wywołasz close() w jednym procesie a potem w drugim to za tym drugim razem nie fejluje. Widocznie po stronie kernela implementacja jest bardziej skomplikowana - nie tylko licznik referencji jest inkrementowany dla file deskryptora ale dodatkowo jeszcze pid procesu pewnie jest dodawany do numeru referencji i stąd takie zachowanie. Jak ktoś się zna na kernelu i mógłby to potwierdzić (2xclose w obrębie 1 procesu - error VS close() w obu procesach - brak errora) to byłbym wdzieczny.
#include "tests.h"
void setOffsetToStart(const int& fd)
{
//start at the beginning of the file
if (lseek(fd, SEEK_SET, 0) == -1)
{
perror("lseek error");
}
}
void read(const int& fd, const int& size)
{
//read data
std::string buffer(size, '0');
int nrOfData = read(fd, &buffer[0], size);
if (nrOfData == -1)
{
perror("Data read error");
}
cout << "read " << nrOfData << " bytes:" << buffer << endl;
}
void write(const int& fd, const char* data, const int& size)
{
//read data
std::string buffer(size, '0');
int nrOfData = write(fd, (void *)data, size);
if(nrOfData == -1)
{
perror("Data write error");
}
cout << "write " << nrOfData << " bytes:" << data << endl;
}
void FileOpenTest()
{
#ifdef LINUX_USED
cout << "FileOpenTest()" << endl;
const char* fileToOpen = "/media/sf_share/mmapTestFile.txt";
int fd = open(fileToOpen, O_RDWR);
if (fd == -1)
{
perror("File %s not opened succesfully");
exit(EXIT_FAILURE);
}
read(fd, 4);
setOffsetToStart(fd);
write(fd, "dupadupa", 4);
setOffsetToStart(fd);
read(fd, 4);
pid_t pid = fork();
if(pid == 0)
{
setOffsetToStart(fd);
write(fd, "ChildProcess", 12);
cout << "Child fd = " << fd << endl;
if(close(fd) == -1)
{
perror("close file error");
}
cout << "Child fd = " << fd << endl;
if(close(fd) == -1)
{
perror("close file error"); //to otrzymuje
}
exit(0);
}
else //macierzysty proces
{
//wait for child exit
int status = 0;
pid = wait(&status);
cout << "Parent fd = " << fd << endl;
read(fd, 12);
}
if(close(fd) == -1) //when process terminates OS do this for you, however it is good practise to close fd
{
perror("close file error"); //tego nie otrzymuje
}
#endif
}
Output programu:
FileOpenTest()
read 4 bytes:Chil
write 4 bytes:dupadupa
read 4 bytes:dupa
write 12 bytes:ChildProcess
Child fd = 3
Child fd = 3
close file error: Bad file descriptor
Parent fd = 3
read 12 bytes:a b c d e f