C#中的安全多线程访问

时间:2017-09-10 19:12:01

标签: c# multithreading windows-forms-designer

我正在尝试实施聊天。我已经采用了代码here

当我发送消息时,我有一个错误:

  

Control' ListMessage'从除以外的线程访问的名称   线程是在它上面创建的。

其中ListMessage是使用Visual Studio添加的ListView。

       private void buttonSend_Click(object sender, EventArgs e)
        {
            //convert string message to byte[]
            ASCIIEncoding aEncoding = new ASCIIEncoding();
            byte[] sendingMessage = new byte[1500];
            sendingMessage = aEncoding.GetBytes(textMessage.Text);
            //sending the encoded message
            sck.Send(sendingMessage);
            //adding to the list box
            listMessage.Items.Add("Me:" + textMessage.Text);
            textMessage.Text = "";
        }

        private void MessageCallBack(IAsyncResult aResult)
        {
            try
            {
                byte[] receivedData = new byte[1500];
                receivedData = (byte[])aResult.AsyncState;
                //converting byte[] to string
                ASCIIEncoding aEncoding = new ASCIIEncoding();
                string receivedMessage = aEncoding.GetString(receivedData);

                //Adding this message into list box
///// error is given in the following line/////
                listMessage.Items.Add("Friend:" + receivedMessage);

                buffer = new byte[1500];
                sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref epRemote, new AsyncCallback(MessageCallBack), buffer);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

我试图按照here所述使用Invoke,但我有错误

        private void MessageCallBack(IAsyncResult aResult)
        {
            try
            {
                byte[] receivedData = new byte[1500];
                receivedData = (byte[])aResult.AsyncState;
                //converting byte[] to string
                ASCIIEncoding aEncoding = new ASCIIEncoding();
                string receivedMessage = aEncoding.GetString(receivedData);

                //Adding this message into list box
                //listMessage.Items.Add("Friend:" + receivedMessage);
                listMessage.AddItemSafe("Friend:" + receivedMessage);

                buffer = new byte[1500];
                sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref epRemote, new AsyncCallback(MessageCallBack), buffer);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void AddItemSafe(string text)
        {
            if (this.InvokeRequired)
            {
                AddItemSafeCallback a = new AddItemSafeCallback(AddItemSafe);
                this.Invoke(a, new object[] { text });
            }
            else
            {
                this.Items.Add(text);
            }
        }

        delegate void AddItemSafeCallback(string text);

Erros是:

  • '列表框'不包含AddItemSafe'的定义。并没有扩展方法。 ' AddItemSafe'接受类型' ListBox'的第一个参数可以找到(你是否错过了使用指令或汇编引用'
  • '的MyUserControl'不包含AddItemSafe'的定义。并没有扩展方法。 '项目'接受第一个类型的参数 可以找到ListBox'(你是否错过了使用指令或者 装配参考'

我的问题:

  • 你是否相信我试图解决最初问题的方式是好的 一个?
  • 如果是,我尝试的解决方案有什么问题 实施

1 个答案:

答案 0 :(得分:3)

是的,这种方法非常正确,但您确实错过了实施的一些内容。

AddItemSafe方法只是表单后代类中的一个方法,而不是listMessage上的方法(可能是任何类型)。因此,当您调用它时,您只需指定方法名称和参数,而不是在另一个对象实例上调用它。

...
ASCIIEncoding aEncoding = new ASCIIEncoding();
string receivedMessage = aEncoding.GetString(receivedData);
//Adding this message into list box
//listMessage.Items.Add("Friend:" + receivedMessage);

// !!!!Note difference here:
AddItemSafe("Friend:" + receivedMessage);
...

然后,在AddItemSafe方法中,您完全按照在单线程环境中执行的操作,即添加到listMessage的项目。如果需要调用,则将整个事物包装到委托中。

private void AddItemSafe(string text)
{
  if (this.InvokeRequired)
  {
    AddItemSafeCallback a = new AddItemSafeCallback(AddItemSafe);
    this.Invoke(a, new object[] { text });
  }
  else
  {
    // !!!!Note difference here:
    listmessage.Items.Add(text);
  }
}