【问题标题】:Is Invoke required?是否需要调用?
【发布时间】:2014-09-17 06:43:03
【问题描述】:

在设置我的套接字进行连接时,我将方法包装在一个 try-catch 块中..

如果引发套接字异常,我会创建一个新线程.. 休眠 15 秒.. 然后再次调用 connect 方法,但这次是从另一个线程调用。我这样做主要是为了睡眠方法(以避免使用计时器重新连接)不挂断主线程。

无论如何.. 尝试连接时,我使用一种名为 Write() 的方法将状态写入文本框,该方法只是将文本附加到当前文本,并在其前添加一个 \n...

因为在连接失败时我创建了一个单独的线程来调用连接方法(它确实修改了表单上的控件),所以我在方法调用上使用调用是正确的吗?

这是我的代码

private void Connect()
    {
        try
        {
            Write("Connecting...");
            _ClientSocket.Connect(new IPEndPoint(IPAddress.Loopback, 2500));
            Connected = true;
            Write("Connected.");
            _ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, 0, new AsyncCallback(RecieveCallBack), null);
        }
        catch (SocketException ex)
        {
            Write("Connection Failed. Trying again in 15 Seconds...");
            Connected = false;
            new Thread(delegate()
            {
                Thread.Sleep(15000);
                Invoke((MethodInvoker)delegate
                {
                    this.Connect();
                });
            }).Start();
        }
        catch (Exception ex)
        {

        }
    }

我只是想确保我以正确的方式执行此操作

【问题讨论】:

  • 测试应该回答你的问题。没有调用它可以工作吗?它适用于调用吗?如果答案分别为“否”和“是”,那么您似乎做了正确的事情。如果答案是肯定的,那么你不需要调用。
  • 你的 UI 框架是什么?我很确定这种做事方式是错误的,尤其是在 C# 5.0 世界中
  • 我看不到您访问 WinForms 的位置。也不要手动创建线程。使用例如 ThreadPool.QueueUserWorkItem
  • 这是个坏主意。除了忘记使用 BeginInvoke() 之外,您还可以通过假设在 Connect() 调用之后连接套接字来创建其他错误。所以咬紧牙关,总是开始一个线程。现在一切都很明显,包括问题的答案。
  • @HansPassant 所以你建议不要在主线程中连接并总是在单独的线程中连接?

标签: c# multithreading winforms sockets exception-handling


【解决方案1】:

您最初可以假设您的连接不会成功,而不是创建线程来连接。这将需要轮询计时器才能重新连接。奖励:您可以控制计时器(虽然您不能对匿名线程做任何事情),您可以将它用于其他需要轮询的任务(重新发送数据,第一次尝试未交付,如果您更改套接字设置,则在断开连接后排队连接等) .

这个轮询计时器可以是一个普通的 UI 计时器(Timer 在 winforms 的情况下),那么你不需要任何调用。如果采用这种方式,请确保其中没有阻塞操作(例如,发送数据和等待应答)。

否则,您可以使用 this 扩展方法让方法始终在 UI 线程中运行

public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
    if (control.InvokeRequired)
        control.Invoke(action);
    else
        action();
}

在您的情况下,您需要像这样调用Write

someUIControl.InvokeIfRequired(() => Write(...));

或者干脆像这样制作Write 方法

void Write(...)
{
    if(someUIControl.InvokeRequired)
        someUIControl.Invoke((delegate)() => Write(...));
    else
    {
        ... job here
    }
}

【讨论】:

  • 除了 Invoke 答案之外,我感谢有关轮询计时器的建议。我知道这会如何更有用。
【解决方案2】:

在所呈现的场景中,它使用new ThreadThread.SleepInvoke 只是作为一种安排一些工作在15 秒内发生在UI 线程上的方式。它会起作用,但是……效率很低(线程是昂贵的)。坦率地说,应该使用计时器 - 或者可能在 4.5 上使用 Task.Delay(实际上它实际上只是包装了一个计时器)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-14
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 2015-10-14
    • 2016-11-09
    相关资源
    最近更新 更多