C#控制线程(恢复/挂起)

本文关键字:挂起 恢复 控制 控制线 线程 | 更新日期: 2023-09-27 18:01:00

我正在尝试模拟(非常基本和简单的(操作系统进程管理器子系统,我有三个"进程"(工人(在控制台上写东西(这是一个例子(:

    public class Message
    {
        public Message() { }
        public void Show()
        {
            while (true)
            {
                Console.WriteLine("Something");
                Thread.Sleep(100);
            }
        }
    }

每个工作线程都应该在不同的线程上运行。我现在就是这么做的:我有一个Process类,构造函数接受Action委托并从中启动线程,然后挂起它

public class Process
{
    Thread thrd;
    Action act;
    public Process(Action act)
    {
        this.act = act;
        thrd = new Thread(new ThreadStart(this.act));
        thrd.Start();
        thrd.Suspend();
    }
    public void Suspend()
    {
        thrd.Suspend();
    }
    public void Resume()
    {
        thrd.Resume();
    }
}

在这种状态下,它会等待调度程序恢复它,给它一个运行的时间片,然后再次挂起它

        public void Scheduler()
        {
            while (true)
            {
                //ProcessQueue is just FIFO queue for processes
                //MainQueue is FIFO queue for ProcessQueue's
                ProcessQueue currentQueue = mainQueue.Dequeue();
                int count = currentQueue.Count;
                if (currentQueue.Count > 0)
                {
                    while (count > 0)
                    {
                        Process currentProcess = currentQueue.GetNext();
                        currentProcess.Resume();
                        //this is the time slice given to the process
                        Thread.Sleep(1000);
                        currentProcess.Suspend();
                        Console.WriteLine();
                        currentQueue.Add(currentProcess);
                        count--;
                    }
                }
                mainQueue.Enqueue(currentQueue);
            }
        }

问题是它不能始终如一地工作。在这种状态下它甚至根本不起作用,我必须在worker的Show((方法中的WriteLine之前添加Thread.Sleep((,就像这样。

        public void Show()
        {
            while (true)
            {
                Thread.Sleep(100); //Without this line code doesn't work
                Console.WriteLine("Something");
                Thread.Sleep(100);
            }
        }

我一直在尝试使用ManualResetEvent而不是suspend/resume,它是有效的,但由于该事件是共享的,所有依赖它的线程都会同时唤醒,而我一次只需要一个特定的线程处于活动状态。

如果有人能帮我弄清楚如何正常暂停/恢复任务/线程,那就太好了。我正在做的是尝试模拟简单的抢占式多任务处理。谢谢

C#控制线程(恢复/挂起)

Thread.Suspend是邪恶的。它和Thread.Abort一样邪恶。在任意、不可预测的位置暂停时,几乎没有任何代码是安全的。它可能持有导致其他线程也暂停的锁。您很快就会在系统的其他部分遇到死锁或不可预测的停顿。

假设您不小心暂停了string的静态构造函数。现在,所有想要使用string的代码也被暂停。Regex内部使用锁定的缓存。如果在执行此锁定时暂停,则所有与Regex相关的代码都可能暂停。这只是两个令人震惊的例子。

挂起Console类内部的某些代码可能会产生意想不到的后果。

我不知道该向你推荐什么。这似乎是一个学术练习,所以谢天谢地,这对你来说不是一个生产问题。用户模式的等待和取消在实践中必须是协同的。

我设法使用带有ManualResetEvent数组的静态类来解决这个问题,其中每个进程都由其唯一的ID标识。但我认为这是一种非常肮脏的方法。我对其他方法持开放态度。UPD:添加锁以保证线程安全

public sealed class ControlEvent
    {
        private static ManualResetEvent[] control = new ManualResetEvent[100];
        private static readonly object _locker = new object();
        private ControlEvent() { }
        public static object Locker
        {
            get
            {
                return _locker;
            }
        }
        public static void Set(int PID)
        {
            control[PID].Set();
        }
        public static void Reset(int PID)
        {
            control[PID].Reset();
        }
        public static ManualResetEvent Init(int PID)
        {
            control[PID] = new ManualResetEvent(false);
            return control[PID];
        }
    }

工人阶级

public class RandomNumber
    {
        static Random R = new Random();
        ManualResetEvent evt;
        public ManualResetEvent Event
        {
            get
            {
                return evt;
            }
            set
            {
                evt = value;
            }
        }
        public void Show()
        {
            while (true)
            {
                evt.WaitOne();
                lock (ControlEvent.Locker)
                {
                   Console.WriteLine("Random number: " + R.Next(1000));
                }
                Thread.Sleep(100);
            }
        }
    }

在流程创建事件

RandomNumber R = new RandomNumber();
Process proc = new Process(new Action(R.Show));
R.Event = ControlEvent.Init(proc.PID);

最后,在调度程序中

public void Scheduler()
        {
            while (true)
            {
                ProcessQueue currentQueue = mainQueue.Dequeue();
                int count = currentQueue.Count;
                if (currentQueue.Count > 0)
                {
                    while (count > 0)
                    {
                        Process currentProcess = currentQueue.GetNext();
                        //this wakes the thread
                        ControlEvent.Set(currentProcess.PID);
                        Thread.Sleep(quant);
                        //this makes it wait again
                        ControlEvent.Reset(currentProcess.PID);
                        currentQueue.Add(currentProcess);
                        count--;
                    }
                }
                mainQueue.Enqueue(currentQueue);
            }
        }

关于Suspend()Resume(),我能给出的最好的建议是:不要使用它。你做错了™.

每当你觉得有人想使用Suspend()Resume()对来控制你的线程时,你应该立即退一步问问自己,你在这里做什么。我知道,程序员倾向于将代码路径的执行视为必须控制的事情,比如一些需要永久命令和控制的愚蠢僵尸工作者。这可能是在学校和大学里学到的关于计算机的东西的一个功能:计算机只做你告诉他们的事情。

女士&先生们,坏消息是:如果你这样做,这被称为"微观管理",有些人甚至会称之为"控制狂思维"。

相反,我强烈鼓励你以不同的方式思考它。试着把你的线程看作是智能实体,不会造成伤害,他们唯一想要的就是得到足够的工作。他们只需要一点指导,仅此而已。您可以将一个装满工作的容器放在他们前面(工作任务队列(,并让他们在完成上一个任务后立即从该容器中提取任务。当容器为空时,所有任务都被处理,没有什么可做的了,它们被允许进入睡眠状态,WaitFor(alarm)将在新任务到达时发出信号。

因此,你没有指挥和控制一群愚蠢的僵尸奴隶,如果你不在他们身后鞭打他们,他们就无法做任何正确的事情,而是故意引导一群聪明的同事,让它发生。这就是构建可扩展体系结构的方式。你不必是一个控制狂,只要对自己的代码有一点信心。

当然,和往常一样,这条规则也有例外。但是没有那么多,我建议从工作假设开始,你的代码可能是规则,而不是例外。