枚举时向哈希表添加新值时出现问题

发布于 2024-08-28 00:03:01 字数 2887 浏览 9 评论 0原文

`嗨,

我正在做一个简单的同步套接字编程,其中我使用了双线程 一个用于接受客户端并将套接字对象放入集合中,另一个线程将 循环遍历集合并通过套接字对象向每个客户端发送消息。

问题是

1.我将客户端连接到服务器并开始发送消息

2.现在我想连接一个新客户端,在执行此操作时我无法更新集合并添加 我的哈希表的新客户端。它引发异常“集合已修改。枚举操作可能无法执行”

如何添加新值而不在哈希表中出现问题。

 private void Listen()
    {
        try
        {
            //lblStatus.Text = "Server Started Listening";
            while (true)
            {
                    Socket ReceiveSock = ServerSock.Accept();
                    //keys.Clear();
                    ConnectedClients = new ListViewItem();
                    ConnectedClients.Text = ReceiveSock.RemoteEndPoint.ToString();
                    ConnectedClients.SubItems.Add("Connected");
                    ConnectedList.Items.Add(ConnectedClients);
                    ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
                    //foreach (System.Collections.DictionaryEntry de in ClientTable)
                    //{

                    //    keys.Add(de.Key.ToString());
                    //}
                    //ClientTab.Add(
                    //keys.Add(

            }
            //lblStatus.Text = "Client Connected Successfully.";
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void btn_receive_Click(object sender, EventArgs e)
    {
        Thread receiveThread = new Thread(new ThreadStart(Receive));
        receiveThread.IsBackground = true;
        receiveThread.Start();
    }
    private void Receive()
    {
        while (true)
        {
            //lblMsg.Text = "";
            byte[] Byt = new byte[2048];
            //ReceiveSock.Receive(Byt);
            lblMsg.Text = Encoding.ASCII.GetString(Byt);
        }
    }

    private void btn_Send_Click(object sender, EventArgs e)
    {
        Thread SendThread = new Thread(new ThreadStart(SendMsg));
        SendThread.IsBackground = true;
        SendThread.Start();
    }

    private void btnlist_Click(object sender, EventArgs e)
    {
        //Thread ListThread = new Thread(new ThreadStart(Configure));
        //ListThread.IsBackground = true;
        //ListThread.Start();
    }
    private void SendMsg()
    {
        while (true)
        {
            try
            {
                foreach (object SockObj in ClientTable.Keys)
                {
                    byte[] Tosend = new byte[2048];
                    Socket s = (Socket)ClientTable[SockObj];
                    Tosend = Encoding.ASCII.GetBytes("FirstValue&" + GenerateRandom.Next(6, 10).ToString());
                    s.Send(Tosend);
                    //ReceiveSock.Send(Tosend);
                    Thread.Sleep(300);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

    }

`hi

I am doing a simple synchronous socket programming,in which i employed twothreads
one for accepting the client and put the socket object into a collection,other thread will
loop through the collection and send message to each client through the socket object.

the problem is

1.i connect to clients to the server and start send messages

2.now i want to connect a new client,while doing this i cant update the collection and add
a new client to my hashtable.it raises an exception "collection modified .Enumeration operation may not execute"

how to add a NEW value without having problems in a hashtable.

 private void Listen()
    {
        try
        {
            //lblStatus.Text = "Server Started Listening";
            while (true)
            {
                    Socket ReceiveSock = ServerSock.Accept();
                    //keys.Clear();
                    ConnectedClients = new ListViewItem();
                    ConnectedClients.Text = ReceiveSock.RemoteEndPoint.ToString();
                    ConnectedClients.SubItems.Add("Connected");
                    ConnectedList.Items.Add(ConnectedClients);
                    ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
                    //foreach (System.Collections.DictionaryEntry de in ClientTable)
                    //{

                    //    keys.Add(de.Key.ToString());
                    //}
                    //ClientTab.Add(
                    //keys.Add(

            }
            //lblStatus.Text = "Client Connected Successfully.";
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void btn_receive_Click(object sender, EventArgs e)
    {
        Thread receiveThread = new Thread(new ThreadStart(Receive));
        receiveThread.IsBackground = true;
        receiveThread.Start();
    }
    private void Receive()
    {
        while (true)
        {
            //lblMsg.Text = "";
            byte[] Byt = new byte[2048];
            //ReceiveSock.Receive(Byt);
            lblMsg.Text = Encoding.ASCII.GetString(Byt);
        }
    }

    private void btn_Send_Click(object sender, EventArgs e)
    {
        Thread SendThread = new Thread(new ThreadStart(SendMsg));
        SendThread.IsBackground = true;
        SendThread.Start();
    }

    private void btnlist_Click(object sender, EventArgs e)
    {
        //Thread ListThread = new Thread(new ThreadStart(Configure));
        //ListThread.IsBackground = true;
        //ListThread.Start();
    }
    private void SendMsg()
    {
        while (true)
        {
            try
            {
                foreach (object SockObj in ClientTable.Keys)
                {
                    byte[] Tosend = new byte[2048];
                    Socket s = (Socket)ClientTable[SockObj];
                    Tosend = Encoding.ASCII.GetBytes("FirstValue&" + GenerateRandom.Next(6, 10).ToString());
                    s.Send(Tosend);
                    //ReceiveSock.Send(Tosend);
                    Thread.Sleep(300);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苍暮颜 2024-09-04 00:03:01

在迭代 Hashtable、Dictionary、List 或任何类似内容时,无论是在同一线程中还是在同一线程中,您都无法修改它另一种。 .NET 4 中有并发集合允许这样做,但我假设您没有使用 .NET 4。(出于兴趣,为什么您仍然使用 Hashtable 而不是通用的 字典?)

也不应该从一个线程修改哈希表,同时在另一个线程中读取它而没有任何同步。

解决此问题的最简单方法是:

  • 创建一个用于锁定的新只读变量
  • 在添加到哈希表之前获取锁:

    锁(tableLock)
    {
        ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
    }
    
  • 当您想要迭代时,在 Hashtable 中创建数据的新副本 > 在锁内

  • 迭代副本而不是原始表

您确实需要这里的哈希表吗?在我看来,一个简单的 ListArrayList 就可以了,其中每个条目要么是套接字,要么可能是包含套接字和任何其他信息的自定义类型你需要。您似乎没有在表上进行任意查找。

You simply can't modify a Hashtable, Dictionary, List or anything similar while you're iterating over it - whether in the same thread or a different one. There are concurrent collections in .NET 4 which allow this, but I'm assuming you're not using .NET 4. (Out of interest, why are you still using Hashtable rather than a generic Dictionary?)

You also shouldn't be modifying a Hashtable from one thread while reading from it in another thread without any synchronization.

The simplest way to fix this is:

  • Create a new readonly variable used for locking
  • Obtain the lock before you add to the Hashtable:

    lock (tableLock)
    {
        ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
    }
    
  • When you want to iterate, create a new copy of the data in the Hashtable within a lock

  • Iterate over the copy instead of the original table

Do you definitely even need a Hashtable here? It looks to me like a simple List<T> or ArrayList would be okay, where each entry was either the socket or possibly a custom type containing the socket and whatever other information you need. You don't appear to be doing arbitrary lookups on the table.

初心 2024-09-04 00:03:01

是的。不要这样做。

这里更大的问题是不安全的多线程。
最基本的“答案”就是说:在共享对象上使用同步锁。然而,这隐藏了许多重要的方面(比如理解正在发生的事情),并且在我看来并不是这个问题的真正解决方案。

Yes. Don't do that.

The bigger problem here is unsafe multi-threading.
The most basic "answer" is just to say: use a synchronization lock on the shared object. However this hides a number of important aspects (like understanding what is happening) and isn't a real solution to this problem in my mind.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文