|
|
|
|
|
|
| Author |
Message |
Valenti Alessandro *nix forums beginner
Joined: 23 Feb 2006
Posts: 2
|
Posted: Wed Mar 01, 2006 10:39 am Post subject:
Re: perform read from shared file descriptor
|
|
|
In my opinion the read function should also move the file offset
"exactly" for the amount of read characters but also the Posix
specification says nothing about the required behaviour.
I know that probably no one needs to read from a shared file descriptor,
but it is interesting for me understand why some OS protects the file
offset change and why some others does not.
Many thanks to Paul for the detailed explaination of Linux model.
Bye
Paul Pluzhnikov wrote:
....
| Quote: | Since there is no semaphore, the parent and child start reading at
the same offset, but then "race" in updating the file offset. This
race may result in either of the processes reading the same data
more then once, and all kinds of other nastiness.
It is somewhat surprising that both APUE and SUSv3 (AFAICT) are
silent on what exactly is supposed to happen when reading shared
file in this manner.
You can also observe [1] the same race in a single multi-threaded
process, where threads read from a *single* file descriptor.
[1] At least on Linux and Solaris 9; on Solaris 10 I got
Sum(N(threadX)) == N(file) |
|
|
| Back to top |
|
 |
Paul Pluzhnikov *nix forums Guru
Joined: 25 Mar 2005
Posts: 512
|
Posted: Mon Feb 27, 2006 12:39 am Post subject:
Re: perform read from shared file descriptor
|
|
|
Valenti Alessandro <avalenti@unimo.it> writes:
| Quote: | I'm experiencing a strange behaviour using standard unix processes.
|
It's only strange if you make incorrect assumptions.
| Quote: | This should be, at least in my intentions, a trivial example about
"how to not use" file descriptors" by showing to my students that if
the child reads some character from a file, then the same characters
will not be read from the father and vice versa.
|
What this example actually shows is that for _read_ access, the
*shared* part of the descriptor (the file offset) is not
protected against simultaneous access, and so all you can really
say is that N(file) <= N(child) + N(parent) (where N is the size
of file or number of bytes that child/parent can read).
| Quote: | When I start running the executable on a medium sized file
(e.g. /bin/bash), I've seen that the sum of the number of read
characters does not match the file size but it is sometimes a little
bigger on Solaris or very greater on Linux 2.4 and 2.6.
|
I have confirmed this (even on small files) on several versions of
Linux, Solaris, and AIX 5.1, but not on HP-UX 11.11, nor on
Solaris 10 (where N(file) == N(child) + N(parent)).
You can see this in the Linux kernel code:
linux-2.6.11.6/mm/filemap.c:
ssize_t
generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{ ...
ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);
... error checks ...
}
ssize_t generic_file_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ ...
down(&inode->i_sem);
ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
up(&inode->i_sem);
... error checks ...
}
Note the absence of semaphore for the read operation.
Since there is no semaphore, the parent and child start reading at
the same offset, but then "race" in updating the file offset. This
race may result in either of the processes reading the same data
more then once, and all kinds of other nastiness.
It is somewhat surprising that both APUE and SUSv3 (AFAICT) are
silent on what exactly is supposed to happen when reading shared
file in this manner.
You can also observe [1] the same race in a single multi-threaded
process, where threads read from a *single* file descriptor.
[1] At least on Linux and Solaris 9; on Solaris 10 I got
Sum(N(threadX)) == N(file)
Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email. |
|
| Back to top |
|
 |
Valenti Alessandro *nix forums beginner
Joined: 23 Feb 2006
Posts: 2
|
Posted: Thu Feb 23, 2006 2:19 pm Post subject:
perform read from shared file descriptor
|
|
|
Dear all,
I'm experiencing a strange behaviour using standard unix processes. I
was working on a simple example for my students as to show them what
happens when You perform concurrent read operation from two different
processes (child and father) on a file opened before of the fork().
This should be, at least in my intentions, a trivial example about "how
to not use" file descriptors" by showing to my students that if the
child reads some character from a file, then the same characters will
not be read from the father and vice versa.
When I start running the executable on a medium sized file (e.g.
/bin/bash), I've seen that the sum of the number of read characters does
not match the file size but it is sometimes a little bigger on Solaris
or very greater on Linux 2.4 and 2.6.
Here my trivial code:
/* file: es71.c
* job: uso della fork
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
char msg[256];
int fd;
int main(int argc, char **argv) {
pid_t fr; /* fork return value */
int st; /* spazio per l'exit value */
int count; /* contatore di read */
char ch; /* spazio per la read */
fd=open(argv[1],O_RDONLY);
if (fd<0) return(-1);
fr=fork();
switch (fr) {
case 0: /* figlio */
count=0;
for (; {
switch (read(fd,&ch,1)) {
case 1:
count++;
break;
case 0:
snprintf(msg,sizeof(msg),"Figlio conta %d\n",count);
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
default:
snprintf(msg,sizeof(msg),"Errore figlio");
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
}
}
break;
case -1: /* errore, nessun nuovo processo */
snprintf(msg,sizeof(msg),"Errore in fork\n");
write(1,msg,strlen(msg));
break;
default: /* padre */
count=0;
for (; {
switch (read(fd,&ch,1)) {
case 1:
count++;
break;
case 0:
snprintf(msg,sizeof(msg),"Padre conta %d\n",count);
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
default:
snprintf(msg,sizeof(msg),"Errore padre");
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
}
}
}
return(0);
}
/* end */
Any opinion should be appreciated. |
|
| Back to top |
|
 |
Google
|
|
| Back to top |
|
 |
|
|
The time now is Sat Nov 22, 2008 11:27 am | All times are GMT
|
|
Teen Chat | MPAA | Home Loan | Free phpBB forum | Remortgages
|
|
Copyright © 2004-2005 DeniX Solutions SRL
|
|
|
|
Other DeniX Solutions sites:
Unix/Linux blog |
electronics forum |
medicine forum |
science forum |
|
|
Privacy Policy
|
Powered by phpBB © 2001, 2005 phpBB Group
|
|