2 fds per thread works well. Unfortunately, this means you hit select's performance problems twice over, since the performance scales with the maximum fd you pass it, not the number of fds. But as long as that's OK for what you're doing, it's a nice way to arrange things.