【问题标题】:Pause And Resume A Thread From Another Thread In C#从 C# 中的另一个线程暂停和恢复一个线程
【发布时间】:2016-03-28 16:08:47
【问题描述】:

我在线程中运行两个函数。一个有一个循环,第二个正在等待输入,所以当输入发生时,它应该暂停第一个循环线程并在同一个第二个线程中要求恢复或终止线程...???

您可以在下面看到我要实现此逻辑的代码...

class Program
    {
        public static int flag = 0;
        public static int process;
        public static int quantum;
        public static int[] execTime = new int[10];
        public static string[] P0 = new string[100];
        public static string[] P1 = new string[100];
        public static string[] P2 = new string[100];
        public static string[] P3 = new string[100];
        public static string[] P4 = new string[100];
        public static string[] P5 = new string[100];
        public static string[] P6 = new string[100];
        public static string[] P7 = new string[100];
        public static string[] P8 = new string[100];
        public static string[] P9 = new string[100];
        public static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This         
            //************************//
            //*** Filling Process ***//
            //************************//
            for (int i = 0; i < P0.Length; i++)
            {
                P0[i] = "P0." + i;                
            }
            for (int i = 0; i < P1.Length; i++)
            {
                P1[i] = "P1." + i;
            }
            for (int i = 0; i < P2.Length; i++)
            {
                P2[i] = "P2." + i;
            }
            for (int i = 0; i < P3.Length; i++)
            {
                P3[i] = "P3." + i;
            }
            for (int i = 0; i < P4.Length; i++)
            {
                P4[i] = "P4." + i;
            }
            for (int i = 0; i < P5.Length; i++)
            {
                P5[i] = "P5." + i;
            }
            for (int i = 0; i < P6.Length; i++)
            {
                P6[i] = "P6." + i;
            }
            for (int i = 0; i < P7.Length; i++)
            {
                P7[i] = "P7." + i;
            }
            for (int i = 0; i < P8.Length; i++)
            {
                P8[i] = "P8." + i;
            }
            for (int i = 0; i < P9.Length; i++)
            {
                P9[i] = "P9." + i;
            }

            //************************//
            //*** Creating Process ***//
            //************************//
            do
            {
                Console.Write("How Many Process You Want To Create? (0-10) ");
                process = Convert.ToInt16(Console.ReadLine());
                if (process > 10)
                {
                    Console.ForegroundColor = ConsoleColor.Red; // Red Color Text Below This
                    Console.WriteLine("Error => Your Process Should Be Less Then 10.");
                    Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This
                }
            } while (process > 10);
            Console.ForegroundColor = ConsoleColor.Green; // Green Color Text Below This
            Console.WriteLine("Success =>" + process + " Process Have Been Generated.");
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This

            //***************************************//
            //*** Creating Process Executing TIme ***//
            //***************************************//
            for (int i = 0; i < process; i++)
            {                
                do
                {
                    Console.Write("What\'s The Executing Time Your Process # " + i + "? (0-100) ");
                    execTime[i] = Convert.ToInt16(Console.ReadLine());
                    if (execTime[i] > 100)
                    {
                        Console.ForegroundColor = ConsoleColor.Red; // Red Color Text Below This
                        Console.WriteLine("Error => Your Executing Time Should Be Less Then 100.");
                        Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This
                    }
                } while (execTime[i] > 100);
            }
            Console.ForegroundColor = ConsoleColor.Green; // Green Color Text Below This
            Console.WriteLine("Success =>" + process + " Executing Time Have Been Generated.");
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This

            //**************************************//
            //*** Resizing Process Array's Steps ***//
            //**************************************//
            Array.Resize(ref P0, execTime[0]);
            Array.Resize(ref P1, execTime[1]);
            Array.Resize(ref P2, execTime[2]);
            Array.Resize(ref P3, execTime[3]);
            Array.Resize(ref P4, execTime[4]);
            Array.Resize(ref P5, execTime[5]);
            Array.Resize(ref P6, execTime[6]);
            Array.Resize(ref P7, execTime[7]);
            Array.Resize(ref P8, execTime[8]);
            Array.Resize(ref P9, execTime[9]);
            Array.Resize(ref P0, execTime[0]);

            //********************//
            //*** Quantum Size ***//
            //********************//
            do
            {
                Console.Write("What's Your Quantum Size? ");
                quantum = Convert.ToInt16(Console.ReadLine());
                if (quantum > execTime.Sum())
                {
                    Console.ForegroundColor = ConsoleColor.Red; // Red Color Text Below This
                    Console.WriteLine("Error => Your Quantum Size Should Be Less Then Total Execution Time.");
                    Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This
                }
            } while (quantum > execTime.Sum());
            Console.ForegroundColor = ConsoleColor.Green; // Green Color Text Below This
            Console.WriteLine("Success =>" + quantum + " Quantum Size Have Been Generated.");
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This

            Thread obj1 = new Thread(processRunning);
            Thread obj2 = new Thread(interrupt);
            obj1.Start();   // Start This Thread
            obj2.Start();    // Start This Thread

        }

        static public void processRunning()
        {
            //***********************//
            //*** Running Process ***//
            //***********************//

            Console.ForegroundColor = ConsoleColor.Green; // Green Color Text Below This
            Console.WriteLine("Process Has Been Started Running...!!!");
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This

            int i = 0;
            while (i < execTime.Sum())
            {
                if (i < P0.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 0");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P0.Length)
                        {
                            Console.WriteLine(P0[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }                
                if (i < P1.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 1");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P1.Length)
                        {
                            Console.WriteLine(P1[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P2.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 2");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P2.Length)
                        {
                            Console.WriteLine(P2[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P3.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 3");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P3.Length)
                        {
                            Console.WriteLine(P3[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P4.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 4");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P4.Length)
                        {
                            Console.WriteLine(P4[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P5.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 5");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P5.Length)
                        {
                            Console.WriteLine(P5[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P6.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 6");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P6.Length)
                        {
                            Console.WriteLine(P6[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P7.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 7");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P7.Length)
                        {
                            Console.WriteLine(P7[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P8.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 8");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P8.Length)
                        {
                            Console.WriteLine(P8[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                if (i < P9.Length)
                {
                    Thread.Sleep(1000);
                    int j;
                    Console.WriteLine("----------------------------------------");
                    Console.WriteLine("Process Identification ID : Process # 9");
                    for (j = i; j < i + quantum; j++)
                    {
                        if (j < P9.Length)
                        {
                            Console.WriteLine(P9[j]);
                        }
                        else
                        {
                            break;
                        }
                    }
                    Console.WriteLine("IR --> " + i);
                    Console.WriteLine("PC --> " + i);
                    Console.WriteLine("Flag --> " + flag);
                    Console.WriteLine("Last Instruction Address --> " + (j - 1));
                    Console.WriteLine("Resume Instruction Address --> " + j);
                    Console.WriteLine("Algorithum --> Round Robin");
                    Console.WriteLine("Quantum --> " + quantum);
                    Console.WriteLine("----------------------------------------");
                }
                // Increment
                i = i + quantum;
            }

            Console.ForegroundColor = ConsoleColor.Green; // Green Color Text Below This
            Console.WriteLine("Process Has Been Completed Running...!!!");
            Console.ForegroundColor = ConsoleColor.White; // White Color Text Below This
            Console.ReadLine();
        }
        static public void interrupt()
        {
            // Intruppt
            ConsoleKeyInfo c = Console.ReadKey();
            if (c.Key == ConsoleKey.Enter)
            {
                flag = 1;
                // Should Pause The First Thread Here And Ask To Continue/Resume Or Kill
            }
            // Intruppt
        }
    }

在这里,我想继续运行processRunning();,直到有人向interrupt(); 提供输入,然后它应该暂停processRunning(); 并等待interrupt(); 函数也允许的恢复,所以逻辑/代码应该是什么背后……???

【问题讨论】:

  • 是的,但我想说清楚,因为一些逻辑也来自背景......
  • 随心所欲。下次我会重点...

标签: c# .net multithreading


【解决方案1】:

您应该记住以下几点:

  1. 它存在描述为here 的 Thread.Suspend 机制,但它已经过时并且有充分的理由,因为:

因为 Thread.Suspend 和 Thread.Resume 不依赖于被控制线程的协作,所以它们具有很强的侵入性,可能会导致严重的应用程序问题,例如死锁(例如,如果您挂起一个线程,该线程持有的资源需要另一个线程)。

因此您可以使用该机制并等待并查看可能的死锁或其他同步错误,或者:

  1. 您可以将该同步逻辑移动到要挂起的线程中,在您的情况下为 processRunning() 方法并执行以下操作:

    while (i

如果您想要更精细的粒度,甚至是在循环中间而不是在每次迭代时停止,您的工作就是根据需要添加更多检查。

您还需要将您的标志声明为volatile,因为该字段由两个线程使用并且需要这样标记:

public static volatile int flag = 0;

这是一个简化的例子:

    private static AutoResetEvent signal = new AutoResetEvent(false);
    private volatile static bool interruptFlag;
    private volatile static bool abortFlag;

    private static void Process()
    {
        //replace true with your condition
        while (true)
        {
            if (interruptFlag)
            {
                if (signal.WaitOne())
                {
                    if (abortFlag)
                    {
                        Console.WriteLine("exiting");
                        return;
                    }
                }
            }

            Console.WriteLine("doing work");

            //.. important work here
        } 
    }

    private static void Interrupt() {
        ConsoleKeyInfo c = Console.ReadKey();
        if (c.Key == ConsoleKey.Enter) {
            interruptFlag = true;
            // Should Pause The First Thread Here And Ask To Continue/Resume Or Kill

            c = Console.ReadKey();

            if (c.Key == ConsoleKey.Escape)
            {
                Console.WriteLine("Interrupting");
                abortFlag = true;
                signal.Set();
            }
            else
            {
                Console.WriteLine("Continuing");
                interruptFlag = false;
                abortFlag = false;
                signal.Set();
            }
        }
    }

    static void Main()
    {
        Thread process = new Thread(Process);
        process.Start();

        Thread interrupt = new Thread(Interrupt);
        interrupt.Start();

    }

【讨论】:

  • 不错的提示,但它没有恢复... :-)
  • 更新答案:按 Enter => 暂停线程;之后按 Escape => 停止线程;按 Escape 以外的任何内容 => 继续。
  • @MuhammadHassan 让我知道此解决方案是否适合您。
  • 感谢您出色而简单的逻辑。我根据我的要求和它的工作对其进行了更多的调整。 :-)
  • 没问题。乐意效劳。 :)
【解决方案2】:

这是 Tamas Ionut 答案的更简单版本。
线程中断不断检查用户输入,当它获得 Enter 键时,易失性中断标志设置为 True,因此线程进程被使用 signal.WaitOne() 阻塞。
通过按 f 信号正在设置,因此进程线程被解除阻塞。

    private static AutoResetEvent signal = new AutoResetEvent(false);
    private volatile static bool interruptFlag;

    private static uint counter = 0;

    static void Main(string[] args)
    {
        Thread process = new Thread(Process);
        process.Start();

        Thread interrupt = new Thread(Interrupt);
        interrupt.Start();
    }

    private static void Process()
    {
        //replace true with your condition
        while (true)
        {
            if (interruptFlag)
            {
                Console.WriteLine("not doing work");
                Console.WriteLine("press F to do work again");

                counter = 0;

                if (signal.WaitOne())
                {
                    Console.WriteLine();
                }
            }

            Console.WriteLine(string.Concat("doing work ", (counter++).ToString()));

            Task.Delay(200).Wait();

            //.. important work here
        }
    }

    private static void Interrupt()
    {
        while (true)
        {
            ConsoleKeyInfo c = Console.ReadKey();
            if (c.Key == ConsoleKey.Enter)
            {
                interruptFlag = true;
                
                c = Console.ReadKey();

                if(c.Key == ConsoleKey.F)
                {
                    interruptFlag = false;
                    signal.Set();
                }
            }
        }
    }

【讨论】:

    【解决方案3】:

    尝试使用 BackgroundWorker 对象(System.ComponentModel)

    BackgroundWorker obj1 = new BackgroundWorker();
    obj1.DoWork += (dowork_s, dowork_e) => {
        ProcessRunning();
    };
    obj1.RunWorkerCompleted += (completed_s, completed_e) => {
        Thread.Sleep(1000);
        if(StillRunning){
            worker.RunWorkerAsync();
        }
        //if not still running, the thread will now terminate
    };
    

    您可以通过调用 obj1.Reset() 暂停线程的执行,并通过 obj1.Set() 继续执行。

    【讨论】:

    • 我更新了我的帖子以使执行更加清晰。您可以将 Thread 对象替换为 BackgroundWorker 对象,并将它们设置为无限循环,直到指定一个标志,此时您可以调用 Reset() 和 Set 以暂停和恢复。
    • 表示我想询问interrupt(); 中的用户,例如您要恢复还是终止? [Y(Resume)/N(Terminate)] 那么该做什么以及在哪里......???你能分享我更新的代码吗????
    • 老实说,从这个冗长的代码段中,我不确定您到底在哪里遇到了麻烦。我正在尽我所能提供如何干净地实现可以动态操作的后台线程的示例,但也许这不是您所需要的。可以更简洁一些,以便更容易为您提供帮助吗?
    • 感谢您的帮助... :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    相关资源
    最近更新 更多