And select() is still a perfectly good option for situations where the number of FDs involved is constant, or at least stays small. For instance: for networking in an X11 application, using a select()-based event loop is much simpler than creating a thread for each socket.
You should never, ever, create one thread per socket. The choice is between select, polled IO, or events.
Sadly, UNIX doesn't have a good unified asynchronous IO model, like OVERLAPPED and IOCP on NT.