【问题标题】:c# How to check a thread is finished before starting another onec#如何在启动另一个线程之前检查一个线程是否完成
【发布时间】:2016-11-30 05:39:50
【问题描述】:

这是我第一次尝试在应用程序中使用线程。 我知道以前有人问过这个问题,但在我看过的解决方案中,我看不出如何在我的情况下应用它们。

我有一个程序,其中每 60 秒在计时器上刷新一个 datagridview。数据来自 SQL 数据库。此计时器还启动一个工作线程以查找特定的蓝牙设备并根据其在后台的发现更新数据库。蓝牙查找特别慢,这就是我将它放在工作线程中的原因。

我的问题是,有时一个新的工作线程会在前一个工作线程完成之前启动。至少这是我得到的错误的唯一合乎逻辑的解释。当唯一可以锁定文件的是来自同一应用程序的另一个工作线程时,最大的问题是文件锁定错误。

这是我用来启动后台线程的代码。

private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
    if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

    // If the user is not on a Remote desktop connection
    if (!remoteDesktopUser)
    {

        // Run the Bluetooth Search in a worker thread
        Thread thread = new Thread(new ThreadStart(this.checkProximity));
        thread.IsBackground = true;
        thread.Start();
    }

    // Load User Data from the DB and display on the screen
    loadUserData();
}

似乎解决方案是使用 thread.IsAlive() 但我一直无法找到一个很好的例子。当我刚刚使用“Thread thread = new Thread()”创建了一个新线程时,尝试检查是否存在线程似乎很奇怪

显然我错过了一些东西。我正在使用 Visual Studio 2008。 感谢您的任何想法 大卫

更新

根据下面 krw12572 提出的解决方案,我尝试了这个...

我将 != 更改为 == 因为我仍然希望每次都在主线程中运行 loadUserData() 方法。

在编辑器中,“_bluetoothSearchThread”上有一个绿色下划线,告诉我该字段从未分配过,并且始终具有 NULL 值。

在运行时,我在此行收到“对象引用未设置为对象的实例”错误。

if (_bluetoothSearchThread == null && _bluetoothSearchThread.IsAlive)

如何分配这个值?

    private Thread _bluetoothSearchThread;
    private void timerScreenRefresh_Tick(object sender, EventArgs e)
    {
        if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

        // Check if Worker Thread is already running.
        if (_bluetoothSearchThread == null && _bluetoothSearchThread.IsAlive)
        {
            if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running");

            // If the user is not on a Remote desktop connection
            if (!remoteDesktopUser)
            {
                // Check if the users mobile phone is within range
                // Run the Bluetooth Search in a worker thread

                Thread thread = new Thread(new ThreadStart(this.checkProximity));
                thread.IsBackground = true;
                thread.Start();
            }
        }
        else 
        {
            if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Worker Thread still running don't start another one");
        }

        // Load User Data from the DB and display on the screen
        loadUserData();
    }

更新 2

好的,我想我已经想通了。 我将 != Null 改回原来的样子,并将 IF 和 Else Around 反过来。

然后我不得不稍微动动脑筋,将“线程”更改为“_bluetoothSearchThread”

现在代码编译并运行。现在我只需要通过触发导致文件锁定错误的条件来测试它,看看我是否真的修复了原始问题。如果可行,我会将 krw12572 答案标记为正确。

更新 2.5 我还必须移动这条线,以免它太快创建新实例

_bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));

所以这是可行的解决方案。

    private Thread _bluetoothSearchThread;
    private void timerScreenRefresh_Tick(object sender, EventArgs e)
    {
        if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");


        // Check if Worker Thread is already running.
        if (_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive)
        {
            // Thread is still running.  Just log it and move on.
            if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "******** Worker Thread still running don't start another one *********");
        }
        else 
        {
            if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running");

            // If the user is not on a Remote desktop connection
            if (!remoteDesktopUser)
            {
                // Check if the users mobile phone is within range
                // Run the Bluetooth Search in a worker thread
                _bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));
                _bluetoothSearchThread.IsBackground = true;
                _bluetoothSearchThread.Start();
            }
        }

        // Load User Data from the DB and display on the screen
        loadUserData();
    }

【问题讨论】:

  • @BALA 我之前确实看到过该解决方案。它似乎过于复杂,我并没有真正理解它。明天我会尝试盲从它,看看是否有可行的东西出来。
  • @AshwinGupta 我已经阅读了那篇文章,它提出了一些不同的选项,但没有解释如何实际使用它们。至少不是我能理解的。

标签: c# multithreading visual-studio


【解决方案1】:

如果您希望一次只运行一个线程,那么您可以创建一个字段来存储 Thread 实例。使用该线程实例,您可以使用_threadInstance.IsAlive 检查它是否已经在运行。

private Thread _bluetoothSearchThread;
private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
    if(_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive) 
        return;        //It means one thread is already performing the search operation.

    if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "");

    // If the user is not on a Remote desktop connection
    if (!remoteDesktopUser)
    {

        // Run the Bluetooth Search in a worker thread
        _bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity));
        _bluetoothSearchThread.IsBackground = true;
        _bluetoothSearchThread.Start();
    }

    // Load User Data from the DB and display on the screen
    loadUserData();
}

【讨论】:

  • 我试过了。它有一些问题。我更新了我的问题以包括您提出的解决方案和错误消息。谢谢大卫
  • 我更新了我的答案。不要创建 Thread thread = new Thread(..),而是使用新创建的字段作为线程实例。 _bluetoothSearchThread = 新线程(...)
【解决方案2】:

编辑:

经过研究,在您的情况下使用 Thread.IsAlive 并不是一种安全的方法。

你应该使用Threa.Join()

文档:

阻塞调用线程,直到 this 表示的线程 实例终止或指定的时间过去,同时继续 执行标准 COM 和 SendMessage 泵送。

示例:

while(!currentThread.Join(0)) //should specify the time if you dont want it to be blocking.
{
    ///thread is ongoing
}
Console.WriteLine("while loop has breaked! so the thread is finished!");

【讨论】:

  • 如何在我的示例代码中使用 Thread.IsAlive。请给我一些想法好吗?
  • @LorenceHernandez 如果前一个工作线程仍在运行,我不想阻塞主线程。只是不要启动另一个工作线程并继续在主线程中处理。主线程将在下一个计时器滴答时再次检查工作线程是否存在。
【解决方案3】:

您可能希望使用Task 而不是Thread

// Create dummy task
Task task = Task.Run(() => { });

private void timerScreenRefresh_Tick(object sender, EventArgs e)
{
    ...
    // add continuation to current task
    task.ContinueWith(t => checkProximity);
    ...
}

新任务只会在前一个任务之后执行。

但是,如果任务在Tick 期间没有时间运行,它们将累积在队列中。

【讨论】:

  • 嗨,Alexander,我正在考虑将任务作为替代方案,尽管我将子任务排队没有意义。我现在了解 krw12572 的建议,并且我上面的解决方案现在有效。为了进行测试,我将计时器刻度设置为 10 秒,我可以从我的日志中看到它正在到处打开和关闭线程。有了上面的代码,就很好了。线程 11 开始,在线程 11 完成之前没有任何其他开始。所以我现在得到的任何其他错误都与重叠线程无关。谢谢你的想法。大卫
猜你喜欢
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
相关资源
最近更新 更多