Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何跟踪所有线程的完成情况。C#_C#_Multithreading_Recursion - Fatal编程技术网

如何跟踪所有线程的完成情况。C#

如何跟踪所有线程的完成情况。C#,c#,multithreading,recursion,C#,Multithreading,Recursion,我需要冻结主线程,直到递归结束。 递归深度=线程数 示例代码: BackgroundWorker backgroundWorker1; Random ran; private void Form1_Load(object sender, EventArgs e) { method(); label1.Text = "Threads is finished"; } private void method() //

我需要冻结主线程,直到递归结束。 递归深度=线程数

示例代码:

    BackgroundWorker backgroundWorker1;
    Random ran;

    private void Form1_Load(object sender, EventArgs e)
    {
        method();
        label1.Text = "Threads is finished";
    }


    private void method() // recursive method
    {

            Thread.Sleep(100);

            backgroundWorker1 = new BackgroundWorker();

            backgroundWorker1.DoWork +=
                new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.RunWorkerAsync();               //Beginning new thread
    }

    private void backgroundWorker1_DoWork(object sender,
       DoWorkEventArgs e)
    {
            ran = new Random();
            Thread.Sleep(ran.Next(500, 1000));
            if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion
            {
                method();
            }
    }

线程完成后,
label1.Text
必须具有值
“线程完成”
。这是怎么做到的

控制台应用程序PoC,它缓存对所有已创建工作进程的引用,并使用数值变量检查有多少工作进程仍在进行中,当该值达到0时-应用程序终止。如果有任何问题,请告诉我

class Program
{
    private static IList<BackgroundWorker> workers;
    private static Random ran;
    private static int activeWorkersCount;

    static void Main(string[] args)
    {            
        workers = new List<BackgroundWorker>();
        DoWork();

        while (activeWorkersCount > 0)
        {
            Thread.Sleep(200);
        }

        Console.WriteLine("Waiting for all workers to finish...");
        Console.ReadLine();
    }

    private static void DoWork() // recursive method
    {
        Thread.Sleep(100);

        var newWorker = new BackgroundWorker();

        newWorker.DoWork += BackgroundWorkerDoWork;
        newWorker.RunWorkerCompleted += (o, e) =>
               {
                  Console.WriteLine("[E] Worker finished");
                  Interlocked.Decrement(ref activeWorkersCount);
               };
        Interlocked.Increment(ref activeWorkersCount);
        newWorker.RunWorkerAsync();
    }

    private static void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        Console.WriteLine("[S] Worker started");
        ran = new Random();
        Thread.Sleep(ran.Next(500, 1000));
        if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion
        {
            DoWork();
        }
    }
}
类程序
{
私营工人;
私有静态随机运行;
私有静态int-activeWorkersCount;
静态void Main(字符串[]参数)
{            
工人=新列表();
销钉();
而(activeWorkersCount>0)
{
睡眠(200);
}
Console.WriteLine(“等待所有工人完成…”);
Console.ReadLine();
}
私有静态void DoWork()//递归方法
{
睡眠(100);
var newWorker=newbackgroundworker();
newWorker.DoWork+=BackgroundWorkerDoWork;
newWorker.RunWorkerCompleted+=(o,e)=>
{
Console.WriteLine(“[E]工作者完成”);
联锁。减量(参考活动工人计数);
};
联锁。增量(参考activeWorkersCount);
newWorker.RunWorkerAsync();
}
私有静态void BackgroundWorkerDoWork(对象发送方,DoWorkerVentargs e)
{
Console.WriteLine(“[S]工作进程已启动”);
ran=新随机数();
Thread.Sleep(run.Next(5001000));
if(ran.Next(1,5)!=1)//if=1则停止递归
{
销钉();
}
}
}

当您决定停止递归时,可以在GUI线程上发布回调。在我的脑海里会是这样的:

if(ran.Next(1,5)!=1)
{
  method();
}
else
{
  Action action=()=>label1.Text = "Threads is finished";
  this.BeginInvoke(action);
}
1) 创建更新Label1的方法:

private void WorkFinished()
{
   if(Label1.InvokeRequired)
   {
      Label1.Invoke(WorkFinished);
   }
   else
   {
      Label1.Text = "Threads is finished";
   }
}
2) 从backgroundWorker1\u DoWork调用WorkFinished()。

您可以使用类:

例如:

using (CountDownEvent countdownEvent = new CountdownEvent(numberOfThreads))
{
    for (int threadIndex= 0; i < numberOfThreads; threadIndex++)
        ThreadPool.QueueUserWorkItem(
            th =>
            {
                DoWork();
                countdownEvent.Signal();
            }, threadIndex);

    countdownEvent.Wait();
}
Console.WriteLine("All threads complete");
使用(CountDownEvent CountDownEvent=新的CountDownEvent(线程数))
{
对于(int-threadIndex=0;i
{
销钉();
倒计时事件。信号();
},螺纹指数);
countdownEvent.Wait();
}
Console.WriteLine(“所有线程完成”);

我使用了一个不稳定的整数,效果很好

BackgroundWorker backgroundWorker1;     
    Random ran;
    long runningThreads = 0;
    public void Start()     
    {         
        method();         
       // Console.WriteLine("Threads is finished");     
    }       
    private void method() // recursive method     
    {
        Interlocked.Increment(ref runningThreads);
        Console.WriteLine("New thread started");
        Thread.Sleep(100);              
        backgroundWorker1 = new BackgroundWorker();              
        backgroundWorker1.DoWork +=                 
            new DoWorkEventHandler(backgroundWorker1_DoWork);             
        backgroundWorker1.RunWorkerAsync();               //Beginning new thread     
    }      
    private void backgroundWorker1_DoWork(object sender,        DoWorkEventArgs e)     
    {             
        ran = new Random();             
        Thread.Sleep(ran.Next(500, 1000));             
        if (ran.Next(1, 5) != 1) // if = 1 then to stop recursion             
        {                 
            method();             
        }
        Finished();
    }
    private void Finished()
    {
        Interlocked.Decrement(ref runningThreads);
        if (Interlocked.Read(ref runningThreads) == 0)
        {
            Console.WriteLine("Threads is finished");     

        }
    }

您正在将一个新的“thread/worker”对象实例分配给现有的和单个
backgroundWorker1
变量,但不确定这是否正确,至少这不正确如果您希望为所有已创建的线程提供支持,则必须对所有已创建的线程/worker实例进行引用我相信此模式称为fork bomb,它的伸缩性不好。正如sll所指出的,这些实例变量不是线程安全的。为什么不提出这个问题,而不是提出一个你已经解决了一半的解决方案呢?代码太傻了,重复启动bgw没有意义。只需使用一个bgw并在DoWork中编写一个循环。在RunWorkerCompleted事件处理程序中设置标签。
CountDownEvent
不适合此解决方案,我认为
numberOfThreads
未知,可以在运行时更改,因为它取决于下一个随机生成的值,因此每个enw线程将调用
random()
并且可能会安排一个新线程,因此您需要递增
numberOfThreads
,而这在
CDE
CountDownEvent也支持添加时是不可能的,只要计数没有达到0(导致事件被设置)@克里斯奇弗斯:谢谢,有道理。正如@chris chilvers指出的,我忽略了倒计时事件的添加可以在递归函数中发生,我就是这样做的。while(activeWorkersCount>0){Thread.Sleep(200);}在第一个线程完成后返回false。在这个问题上。。。如果你觉得舒服,就用你自己的语言说。我是俄罗斯人,创建一个线程可以是几十个。我需要在完成所有线程时获取消息当
if(activeWorkersCount>0)
返回false时,这意味着没有工作线程被调度。在这种情况下,第一个线程完成时返回false。我检查了我提供的控制台应用程序还是您的?您是否对嫁妆进行了任何更改?如果是这样,请在我提供的控制台应用程序中更新代码或演示如何复制此代码,可能会导致在增量runningThreads++之前检查(runningThreads==0)。因为您没有使用锁?这就是我使用volatile intvolatile关键字的原因。volatile关键字将确保您不会从缓存中读取变量,但它能保证避免这里的争用条件吗?例如,检查以下步骤:1。减量运行线程2检查运行线程==0且在控制台语句3之前:另一个线程开始执行并递增运行线程,对吗?这就是使用联锁递增、联锁递减和倒计时事件的原因?