I never said clients call accept. Obviously its the server end. I said as an example, client[2] is LOCKED in the accept() loop. And if you attempt to change the index of the array through another thread, and a client connects to the server, it still accepts client[2] rather than whatever index you are wanting.
This is called a race condition. This is NOT considered thread safe programming.
The only thread that should be resizing or messing with your socket array should be the one calling accept().
What you may want to do is only make changes to the array in the accept() thread.
You will need to provide a pointer to the socket in the array (like &sockets[x] ) so that the client thread can assign a "kill me I'm disconnected" value (invalid socket) to it in the array without knowledge of the array.
The thread that calls accept() will reuse these invalid socket spots by putting a valid socket in there and creating a new thread like before.
However, this approach is flawed because.....
it looks like you are going to attempt to send data from one thread and recv data from another thread on the same socket without using some sort of synchronization.
Using a mutex is really not optional in this situation.
The ideal case is to actually just pass the data to the other threads that own the client sockets (have like a linked list of your message objects protected by a mutex).
Other threads can add messages by calling a method from your server_client class and passing data that is shoved into the list. The thread that owns the socket will call a method that removes the oldest message from this list and then you send() it.
Otherwise I might as well say that multithreading a simple chat program isn't possible and resort to asyncronous or select.
it's entirely possible. The problem is you are making the assumption that you can just throw single-threaded mindset coding into a multithreaded project and have it work.
Writing code for multithreading is really a big task in itself. Multithreading itself is more complicated than networking.
LOL. I'm adding this edit because my original reply didn't make sense when I came back and read it....
Try this:
Encapsulate your server's sessions (a session is defined as a server-to-client relationship) using a server_client class (not using C++ but just C? use a struct to store it- C can be fairly object-ty if you want it to be).
Each server_client represents 1 thread, 1 socket (, and 1 id in this example i guess).
Each server_client has an outgoing message queue. Other server_clients add to this queue and never touch the socket directly.
Each server_client will check this queue for new messages and send() them out. (USE A MUTEX to prevent more than one thread from resizing this queue at the same time)
Somewhere there needs to be a list of server_client's (also protected by a mutex!) and every server_client will need to have access to this list for "broadcasting" messages out.
When the connection is closed, the server_client has code you call ( server_client->isClosed() ). The thread that accepts connections and spins up server_client's will have to be the one that deletes closed server_client's from the list.