Usually it is a good idea to run your entire game so it is owned by one thread.
You can have one thread (a different thread) that runs `select` on your sockets to get notified of new incoming packets. This thread simply pulls packets off of the sockets and queues them up. Each game instance, owned by one thread, has a queue of incoming packets. The select thread just pushes packets onto these queues. Each game instance pulls packets out of these queues whenever they are looking for new information (like once per update loop, via polling).
select should work pretty well up to a certain point in scale. I have no experience with scaling select really high, but personally I do not imagine it will cause problems for anyone on these forums. I do know other MMO games have used things like epoll/kqueue for Linux, or IOCP on Windows. I don't think you need to read into these strategies, but I'm just posting about them here for posterity at this point
For my game I'm using UDP, so I just have a dedicated thread that pulls data off of a single UDP socket and queues them up for other threads to consume. TCP is slightly more complicated since each connection will have a different socket, hence requiring something like `select`. C# definitely will have some kind of select function exposed. You will have to search for it, since I don't know C# very well.