【问题标题】:C# Start Stop Thread with ManualResetEventC# 使用 ManualResetEvent 启动停止线程
【发布时间】:2018-08-08 08:54:57
【问题描述】:

编辑:我已从 Run() 方法中删除了 .Sleep(5000),并用模拟复杂计算的双循环替换了它。

我想了解如何使用ManualResetEvent 控制线程? 我写了一段简单的代码,它应该启动、停止和恢复前台线程,但它没有按预期工作。

using System;
using System.Threading;

namespace ThreadHandler
{
    public class Engine
    {
        public static ManualResetEvent ThreadHandle;
        public static void Run()
        {
            Random rng = new Random();
            ThreadHandle = new ManualResetEvent(true);
            while (true)
            {
                ThreadHandle.WaitOne();
                for (int i = Int32.MaxValue; i > 0; i--)
                {
                    for (int j = 0; j < rng.Next(); j++)
                    {
                        int res;
                        int div =    
Math.DivRem(Math.Abs(Convert.ToInt32(Math.Floor(Math.Log(rng.NextDouble()) / 
Math.Log(rng.NextDouble())))),                           
Math.Abs(Convert.ToInt32(Math.Floor(Math.Log(rng.NextDouble()) /Math.Log(rng.NextDouble())))) + 1, out res);
                        double calc = Math.Sin(Math.Sqrt(div)) * Math.Cos(Math.Sqrt(res));
                    }
                    if (i % 500 == 0)
                        Console.WriteLine("This engine is working hard!!!");
                }
            }
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            Thread engine = new Thread(Engine.Run);
            int cnt = 100;
            while (cnt-- > 0)
            {
                Console.WriteLine("\nThread status: " +  engine.ThreadState);
                Console.WriteLine("Enter command line (Start/Wait/Set/Status/Quit)");
                string cmd = Console.ReadLine();
                switch(cmd.ToUpper())
                {
                    case "START":
                        engine.Start();
                        break;
                    case "WAIT":
                        Engine.ThreadHandle.WaitOne(Timeout.Infinite);
                        break;
                    case "SET":
                        Engine.ThreadHandle.Set();
                        break;
                    case "STATUS":
                        Console.WriteLine("  >" + engine.ThreadState);
                        break;
                    case "QUIT":
                        cnt = 0;
                        break;
                    default:
                        Console.WriteLine("Unknown command");
                        break;
                }
            }
            engine.Abort();
        }
    }
}

当我运行程序时,线程未启动:

线程状态:未启动 输入命令行(开始/等待/设置/状态/退出)

启动线程后,事情变得很奇怪。 ThreadState 立即从 Running 变为 WaitSleepJoin。这是什么原因?我认为线程将保持在运行状态,直到我们调用方法 WaitOne()

编辑:线程启动,其ThreadState 逻辑上是Running

线程状态:未启动 输入命令行(开始/等待/设置/状态/退出) 开始 线程状态:正在运行 输入命令行(开始/等待/设置/状态/退出) 这个引擎辛苦了!!! 地位 >跑步

然后当我输入Wait时,线程停留在WaitSleepJoin,但引擎继续运行。

编辑:我现在遇到的问题是如何阻止它?当我打电话时

Engine.ThreadHandle.WaitOne(Timeout.Infinite);

线程继续运行:

线程状态:未启动 输入命令行(开始/等待/设置/状态/退出) 开始 线程状态:正在运行 输入命令行(开始/等待/设置/状态/退出) 这个引擎辛苦了!!! 地位 >跑步 线程状态:正在运行 输入命令行(开始/等待/设置/状态/退出) 这个引擎辛苦了!!! 等待 线程状态:正在运行

最后,当我输入 Set 时,线程永远不会回到运行状态。

我的问题仍然是:

  1. 如何中断线程Enginebay 调用方法WaitOne()
  2. 之后如何恢复?

【问题讨论】:

  • 引擎线程位于WaitSleepJoin 中,因为您在其中有Sleep 命令。您的引擎线程需要调用 Wait one - 现在是您的“主”控制台线程执行此操作...
  • 谢谢你 fredrik,我已经添加了 ThreadHandle.WaitOne();在我的Engine 循环中,但引擎线程在启动后不断更改为WaitSleepJoin
  • 它会继续这样做,因为它正在睡觉......首先在.Sleep(),然后在WaitOne()
  • 我删除了.Sleep(5000),它现在一直在运行,但仍然无法暂停。
  • Run() 方法中的代码非常非常慢。一旦你让它运行,它将运行相当长的时间,似乎没有任何影响。您需要对其进行调整以使其与您的耐心兼容,减少循环,使其永远不会超过 50 毫秒。

标签: c# multithreading resume manualresetevent


【解决方案1】:

你的WaitOne() 永远不会工作,因为它在主循环中,而执行的代码在后面(两个 for 循环)。
您需要将其向下移动:

while (true)
{
    for (int i = Int32.MaxValue; i > 0; i--)
    {
        for (int j = 0; j < rng.Next(); j++)
        {
            ThreadHandle.WaitOne();
            // ...
        }

        if (i % 500 == 0)
            Console.WriteLine("This engine is working hard!!!");
    }
}

结果

Thread status: WaitSleepJoin
Enter command line (Start/Wait/Set/Status/Quit)

注意
我相信你错过了使用 ManualResetEvent 因为 WaitOne 方法需要被谁会等待(在你的情况下是线程)调用,但你调用它两次。您可能应该使用布尔值向线程发出信号,表明它应该启动WaitOne

【讨论】:

  • 好的,现在我使用static 布尔值来了解何时调用WaitOne()。我试图避免使用该解决方案,因为每次更改变量时我都需要锁定它。 Thread 转了一会儿WaitSleepJoin,然后又自己重新开始了。即使我使用WaitOne(Timeout.Infinite)。有没有办法让它等到我打电话给.Set()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多