2

I develop the server in C# and have a question:

Let's say I have the List <Socket>, it have 20 objects, from the first object (socket) comes a message that I must:

  • duplicate to all objects in the worksheet

or

  • duplicate to one particular object

Everything works correctly, if it is currently work one thread with List <Socket>. But if to List <Socket> suddenly turn 20 threads simultaneously (message arrived from everyone), which not only pass on the List and send a message, but also on the basis of the contents of the messages can close the socket and remove it from the List, then I do not know how to create atomic access and not lose productivity.

String targetIp, msg;

lock(socketListMutex)
{
    for(int i = 0; i < listSocket.Count; ++i)
    {
        if(listSocket.elementAt(i).targetIp == targetIp)
        {
            listSocket.sendTo(msg);
            break;
        }
    }
}

Edit 1:

What can happen:

  • One of the 20 falls off.
  • The list is removed fallen off the socket, and it was in the beginning. As a consequence - the list has shifted to the left.
  • At this time all of the sent message and stood in the middle of the cycle. As a result - missed one socket.
Amazing User
  • 3,473
  • 10
  • 36
  • 75
  • Id say use a mutex, but the code sample you provided has one. Is the code sample what you want to do or what you have done or what is working or what isn't working? – Serdalis Feb 02 '14 at 22:13
  • That's what I did. Need to modify something (Edit 1) – Amazing User Feb 02 '14 at 22:18
  • 1
    @dima Your loop won't be running at the moment of removing of list's element as long as you use `lock` properly throughout your code - that's what's it for. Your scenario will never happen then. – BartoszKP Feb 02 '14 at 22:30

1 Answers1

1

The following is based on my understanding of your question, while I'm not quite sure I understood it correctly.

A solution could be as simple as making a copy of the list of sockets, before processing it:

Socket[] sockets;
lock (socketListMutex) 
    sockets = listSocket.ToArray();

foreach (socket in sockets)
{
    // check the state of each socket object
    // and send a message if needed
}

Your requirements don't mention the situation when a new message arrive (possibly on a different socket) before the previous one has been fully processed. In this case, some additional logic would be required to preserve the order of the messages, like queuing.

On a side note, I don't think you need additional threads. Use asynchronous APIs instead:

foreach (socket in sockets)
{
    // send a message to each socket
    await Task.Factory.FromAsync(
        (asyncCallback, state) =>
            socket.BeginSend(buffer, offset, size, socketFlags, asyncCallback, state),
        (asyncResult) =>
            request.EndSend(asyncResult));
}

More on asynchronous socket operations:

Awaiting Socket Operations.

Some thoughts about the threading model of a TCP server app:

https://stackoverflow.com/a/21018042/1768303

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486