当前位置:编程学习 > C#/ASP.NET >>

使用Thread.Sleep来暂停线程时遇到的问题...

想实现的功能其实很简单...就是在主程序里调用三个线程,而只有当三个线程都完成了以后才继续执行主程序下面的语句..

程序的思路大概是这样的..

main()

{
   finishedThread = 0;
   Start Thread1;
   Start Thread2;
   Start Thread3;
   While (!finishedThread==3)
        {
            Thread.Sleep(5000);
        }
   Messagebox.Show ("All threads finished");
}

Thread1()
{
   .......
   finishedThread++;
}

Thread2和Thread3类似。。


但这样运行的结果却很奇怪...当Main里调用Thread.Sleep后似乎连从Main里启动的3个线程也一起停下了..造成这3个线程没有一个能够完成执行的...所以Main也就被卡在那个while循环里面了..用分布调试也会发现一直在while循环里跳来跳去...完全不运行那3个线程里的代码了...

一直觉得各个线程之间是完全独立的..Thread.Sleep应该只能暂停当前的线程啊...难道不是这样吗...

请各位大虾指教下了....要实现这样的功能应该怎么写的。。谢谢谢谢了 --------------------编程问答--------------------

int finishedThread   =   0; 
object syncobj=new object();
main() 

      Start   Thread1; 
      Start   Thread2; 
      Start   Thread3; 
      While   (!finishedThread==3) 
      { 
            Thread.Sleep(5000); 
      } 
      //使用While來阻塞線程是可以的,但是更好的方法應該使用線程的Join方法,如下:
       //Thread1.Join();
      //Thread2.Join();
      //Thread3.Join();
      //注:使用了Join方法後,沒有必要再使用finishedThread++,當前線程會等待調用Join方法的線程結束後才繼續運行。
      Messagebox.Show   ("All   threads   finished"); 


Thread1() 

      ....... 
      lock (syncobj)
      {
           finishedThread++;
      }
 


--------------------编程问答-------------------- 谢谢LS的朋友..我去试一下用Thread.Join方法..

但是我还是不明白用Thread.Sleep来等待为什么会有问题..在分步调试时发现..Thread1/2/3里面的代码仅仅在Main里里已经启动了线程但是还没有执行到Thread.Sleep的时候才会执行一小部分..一旦主程序执行到Thread.Sleep就被卡死在While循环里面..貌似是Thread1/2/3就不会继续往下执行了..我在finishedThread++那里设的断点永远都没有被执行到.. --------------------编程问答-------------------- 但是我还是不明白用Thread.Sleep来等待为什么会有问题.在分步调试时发现..Thread1/2/3里面的代码仅仅在Main里里已经启动了线程但是还没有执行到Thread.Sleep的时候才会执行一小部分..一旦主程序执行到Thread.Sleep就被卡死在While循环里面..貌似是Thread1/2/3就不会继续往下执行了..我在finishedThread++那里设的断点永远都没有被执行到..
----------------------------------------
通常不會有這種情況,肯定是你沒有貼出來的代易做图有問題,好好檢查一下 --------------------编程问答-------------------- 你这样的代码肯定是3个线程同时停了。可以定义一个对象,使用lock

欢迎访问http://www.ccworker.com --------------------编程问答-------------------- LS的朋友能说的再详细一点吗... 

也就是说Thread.Sleep是暂时停止所有线程吗。 --------------------编程问答--------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

//展示用Monitor访问共享资源
namespace UseMonitor1
{
    class Program
    {
        static void Main(string[] args)
        {
            SharedResource obj = new SharedResource();

            Thread[] ths = new Thread[4];
            for (int i = 0; i < 4; i++)
            {
                ths[i] = new Thread(increaseCount);
                ths[i].Start(obj);
            }
            System.Console.ReadKey();


        }
        static void increaseCount(Object obj)
        {
           //访问实例字段
            VisitDynamicField(obj);
            //访问静态字段
            VisitStaticField();

        }

        //访问静态字段
        private static void VisitStaticField()
        {
            //访问静态字段
            Monitor.Enter(typeof(SharedResource));
            int beginNumber = SharedResource.StaticCount;
            System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1}  ", Thread.CurrentThread.ManagedThreadId, beginNumber);
            for (int i = 0; i < 10000; i++)
            {
                beginNumber++;

            }
            SharedResource.StaticCount = beginNumber;
            System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
            Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
           Monitor.Exit(typeof(SharedResource));
        }

        //访问实例字段
        private static void VisitDynamicField(Object obj)
        {

             Monitor.Enter(obj);
            //lock (obj)
            //{
                int beginNumber = (obj as SharedResource).DynamicCount;
                System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1}  ", Thread.CurrentThread.ManagedThreadId, beginNumber);
                for (int i = 0; i < 10000; i++)
                {
                    beginNumber++;

                }
                (obj as SharedResource).DynamicCount = beginNumber;
                System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
                Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
            //}
                Monitor.Exit(obj);
            
        }
    }
    //共享资源类
    class SharedResource
    {
        public int DynamicCount = 0;        //多线程共享的实例字段
        public static int StaticCount = 0;  //多线程共享的静态字段

    }
}

--------------------编程问答-------------------- lz。你程序的问题不是因为Thread.sleep将3个进程都sleep了。你说一直在while中循环不跳出去,是因为你的几个线程没有同步。当3个线程执行完以后,finishedThread不为3,所以不断死循环。加上同步机制后就可以了。 --------------------编程问答-------------------- 谢谢6楼的朋友..我研究下代码

7楼的朋友..我设了断点在finishedThread++上..在while里面死循环的时候完全就没有运行过finishedThread++这个语句.. --------------------编程问答-------------------- 我设了断点在finishedThread++上..在while里面死循环的时候完全就没有运行过finishedThread++这个语句..
--------------------------
那個是在輔助線程中執行,你在主線程中調試,當然捕捉不到。

LZ貼出Thread1的代易做图. --------------------编程问答-------------------- Thread1/2/3的代码是很简单的。就是通过Webclient来下载一个文件

类似与

Private void thread1()
{
   WebClient wc = new WebClient();
            //下载文件
            try
            {
                wc.DownloadFile(filepath, localpath);
            }
   FinishedThread++;
}

我试了下用Thread.Join倒是可以实现这个功能..但问题是窗体在Thread.Join的等待时貌似会被锁死...窗体上的控件(比如说最小化按钮)在等待过程中都无易做图常试用了...不知道应该怎么解决。。麻烦LS的朋友了。。 --------------------编程问答--------------------
using System;
using System.Threading;
//完整的测试线程的例子,直接运行看看就明白了
public class CreateThreading
{   
    Thread ThreadA, ThreadB; int addSum;
    int intArg;
    static void Main(string[] args)
    {//启动时加上运行参数后,主线程等待B线程运行结束才继续向下执行
        CreateThreading myCThr = new CreateThreading();
        myCThr.intArg = args.Length;
        for (int i = 0; i < myCThr.intArg; i++) Console.WriteLine(args[i]);
        myCThr.Start(); 
    }
    public void Start()
    {
        ThreadStart myThreadStart1 = new ThreadStart(PrintOddNumber);
        ThreadA = new Thread(myThreadStart1);
        ThreadA.Name = "A ";
        //ThreadStart myThreadStart2 = new ThreadStart(PrintNumber);
        ThreadB = new Thread(new ThreadStart(PrintNumber));
        ThreadB.Name = "B ";
        ThreadA.Start();
        ThreadB.Start();
        if (intArg > 0) ThreadB.Join();//此句表示当前线程被暂停,线程2结束后,后面的语句才被执行
        //同步线程问题
        CreateThreading mycls = new CreateThreading();
        Thread[] Theads=new Thread[3];
        for (int i = 0; i < 3; i++)
        {
            Theads[i] = new Thread(new ThreadStart(mycls.DoSum));
            Theads[i].Name =i.ToString();
            Theads[i].Start();
        }
        Thread.Sleep(100);//主线程在此等待的时间
        Console.WriteLine("---------------主线程结束,其他线程仍要执行完毕-------------------");
    }
    private void PrintOddNumber()
    {
        for (int i = 0; i < 30; i++)
        {
            if (i % 2 != 0)
            {
                Console.WriteLine("线程{0}输出奇数{1}", Thread.CurrentThread.Name, i);
                Thread.Sleep(20);
            }
        }
    }
    private void PrintNumber()
    {
        for (int i = 0; i < 20; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("\t线程{0}输出偶数{1}", Thread.CurrentThread.Name, i);
                Thread.Sleep(20);
            }
            if (i > 10)  ThreadA.Join(100);// 当运行到100时当前线程被停止直到线程1运行完毕才返回继续
        }
    }
    void DoSum()
    {
        for (int i = 0; i < 10; i++)
        {
            lock (this)
            {
                addSum += 2;      Thread.Sleep(10);
                int m = int.Parse(Thread.CurrentThread.Name);
                string st = new string('\t', m);
                Console.WriteLine(st + "\t\t\t\t线程" + Thread.CurrentThread.Name + " 执行第" + i + "次,AddSum=" + addSum);
            }
        }
    }
}
--------------------编程问答-------------------- 你sleep的不是mian线程么?就是窗体线程 --------------------编程问答-------------------- While   (!finishedThread==3) 能这样写的吗? --------------------编程问答-------------------- 谢谢上面的各位解答...

用Thread.Join或者Thread.Sleep已经能够实现上面提到的问题了..不过还有一个问题就是在等待子线程执行完成的时候,主线程(也就是MAIN)的窗体控件都无法使用~~ 这应该是因为主窗体所在的线程被挂起的缘故...但不知道要怎么样才能让主窗体在等待其余子线程时也能让控件正常工作,比如说最小化按钮等。

我试着让主窗体(线程A)先开启另外一个额外的线程(线程B),然后在线程B里再开始调用3个子线程。。但发现在线程B里用Join或者Sleep的时候...主窗体的控件同样无法使用。。

再次谢谢了

--------------------编程问答-------------------- 自己顶一下。。。谢谢大家
--------------------编程问答-------------------- 你要做的事应该用窗体的Invoke来实现,可以搜一下
补充:.NET技术 ,  C#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,