![]() | |||||||||||||
Messages in this thread |
I just got caught up on 3 days worth of interesting discussion; here are some points that I didn't see made. Everything I say here about poll() applies equally to select(), of course. Someone said that if regular files supported poll(), "tail -f" could use poll() instead of sleep(). This is not true; it is a common misconception about what poll actually does. A poll for reading doesn't mean "wake me when there are data which I can read". It means "wake me when a read() would not block interruptibly. A read() on a regular file will never block interruptibly (at least by tradition, interruptible NFS mounts notwithstanding). Regular files already support poll() fully and correctly. Someone said that poll on regular files is the same as async I/O. It isn't. poll isn't I/O at all. Operations under any async I/O paradigm actually perform I/O and notify asynchronously of completion. poll never performs I/O, it only gives the caller stale information about whether certain hypothetical I/O operations would block. This is one of the flaws in select, poll, ioctl(FIONREAD) and similar kludges. Between the time that the call returns and the time you try to do something about it, things can change. If you are correctly using non-blocking operations, this is probably only a performance problem (you would just loop back into another poll), but if you assume that the information from poll is more than a hint, you can reach deadlock or some other failure. True async I/O requires that the actual I/O be asynchronous, not just a mechanism for waiting until it is safe to do synchronous I/O. Someone claimed that poll() could benefit from a wake-one implementation or option. This doesn't make sense for two reasons. First, it just doesn't make sense to have more than one context polling for the same readiness condition, for the reasons above. Second, after the chosen thread is awoken, what should happen to the other polling threads? They are still in a poll() system call, one of the file descriptors they are polling is ready, and there is no real guarantee that the awoken thread will do anything with the ready fd any time soon. It may have other ready fds or other internal processing to do first, or just be hosed in general. The situation is one where the semantics of poll() say that the other threads should wake up, but you "don't want" them to, but there is no reasonable condition defined for when this special exception period should end. poll() is a substitute for multithreading and just wasn't meant to work well in conjunction with multithreading. Because of the nature of poll() it is most robust to multiplex your polling of any one condition through one thread and pass off the events to other threads, even though this has unfortunate performance costs. Someone wondered what it would mean to be polling a file descriptor and have that file descriptor become closed (either by closing it in another thread, or by using some new asynchronous form of polling). The proper semantics of poll() say that the poll should immediately report the closed file descriptor as "ready" because a read() would not block, it would immediately return (with EBADF). Some people proposed various forms of asynchronous I/O or asynchronous polling. Asynchronous I/O is not a bad idea, but it is a very different paradigm from that of Unix. I find the idea of asynchronous polling, however, absolutely hideous. It just adds a messy, complex interface on top of a flawed incomplete alternative to true threads. An asynchronous programming model would be much better based on true async I/O, with completion messages indicating that the I/O is complete. But all currently implemented or proposed asynchronous I/O schemes (of course there probably some of which I am not aware) are still incomplete alternatives to threads. There are many operations for which one needs to wait that are not strictly I/O operations, or at least do not use the read/write/file descriptor model. Examples: wait(), connect(), pause(). Threads are really the only way to get everything right. The idea of implementing async I/O on top of threads seems completely backward to me. If I were designing and implementing a OS from scratch, I would have the kernel provide only asynchronous I/O, and no threads. Every single system call would be asynchronous in structure, although most operations would no doubt be marked as already completed when the trap returned. One version of libc would wrap these asynchronous calls inside synchronous wrappers, doing an explicit wait for completion after every call, providing a traditional Unix-like model. Another version of libc would implement threads, doing a wait for completion only when all threads were sleeping. Another version of libc could make the asynchronous interfaces themselves available. Note that the above hypothetical system fails to give any parallelism benefit to a single running process on a MP system. This is fine by me. Threads are a programming paradigm, not a perfomance tool. If you want parallelism, use fork(). I'm sure at least that last statement will get some disagreement. :) -=] Ford [=- "God shuffled his feet (In Real Life: Mike Ditto) and glanced around at them. ford@omnicron.com The people cleared their throats http://www.omnicron.com/~ford/ford.html and stared right back at him." - Crash Test Dummies - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu | ||||||||||||
| Last update: 2005-03-22 12:43 [W:4.309 / U:0.030 seconds] ©2003-2008 Jasper Spaans | |||||||||||||