我想通过循环10次,对同一方法运行10个线程,但限制同时运行的线程为3个,其余等待。但我运行了好多好多次,总是不能完成10个线程,有时8个,有时9个。想了好久就是不明白。可能旁观者清,大家看看。刚开始编程,左拼右凑的,见笑了   :)请高手指点一下菜鸟,不胜感激!!
using System;
using System.Threading;public class T
{
public int chk;
public int i;
public int num = 0;

public T(int a,int b)
{
chk = a;
i = b;
} public void go()
{
Monitor.Enter(this);
chk++;
Monitor.Pulse(this);               //每进行完一个线程,激活一个等待的线程
Monitor.Exit(this);
num++;
Console.WriteLine("#"+num+"=done=i:" + i+"==chk:"+chk);  //用#标识
}
}public class A
{
public static void Main()
{
T b = new T(3,0);                    //初始化chk=3,i=0
int nums = 0;

for(;b.i<10;b.i++)                  //循环10次,产生10个线程
{
Monitor.Enter(b);
ThreadStart myThreadDelegate = new ThreadStart(b.go);
Thread myThread = new Thread(myThreadDelegate);
Console.WriteLine("in==i:" + b.i+"==chk:"+b.chk);
myThread.Start();               //线程调用go方法
b.chk--;                       
if(b.chk <= 0)                  //限制同时进行的线程为3个,当达到3时等待
{
nums++;
Console.WriteLine("@@@@"+nums+"wait==i:" + b.i+"==chk:"+b.chk);//用@标识
Monitor.Wait(b);
}
}
Console.WriteLine("F-END==i:" + b.i+"==chk:"+b.chk);
}
}
数一下#done的,总是没有10个,就是说没有10个线程完成,可明明循环了10次,为什么啊,头好大

解决方案 »

  1.   

    楼主,不要怪我说你,你的逻辑完全就是个错滴,不晓得你是怎么产生这样的想法的。1.Monitor是用来在单个资源上进行加锁,.Enter和.Eixt方法是成对出现的,在你的程序中,这个就不配对,你没注意到吗?你的程序执行完所有操作后,并没有终止。2.你怎么能够在类的内部还对this来加个锁?我无法理解,我也真搞不懂这样的程序是怎么可以运行的。(对于Monitor内部的机理我不清楚)3.你限制程序到达3时等待,实际上到2时就已经等待了,把这句if(b.chk <= 0);中的等号去掉。给你建议:
    1.你若想真的看到同步的情况,可以具体考虑一下:go方法执行5秒钟,for循环1秒钟循环一次,这个可以考虑用Thread.Sleep(1000);放到for语句块的第一句,或者用Timer来实现。这样一步一步你可以看得很清楚。2.加锁时,是在线程对互斥资源访问前加锁,在你的程序里,完全看不出来是对什么加锁,你把加锁的语句放到了go方法里面去了,因为go方法里没有涉及到互斥资源,看得出,你的本意是在对go方法加锁,是吗?如果是,你的做法就不对了。
      

  2.   

    我刚才查看了一下MSDN,没有看到,对于拥有多个资源来互斥的类,这句话我表达不清楚,头晕了,明天再搞。[email protected],愿联系交流,我目前也正在学习C#
      

  3.   

    可能我的思路是不对,但是似乎确实达到了限制3个线程的作用,只是最后好像有些线程没有给pulse出来。早上又运行了,运气好有一次完成了整个过程。所以我觉得我不是完全错了,只是运行的时候有些因素考虑不到,所以有时没有办法完全完成
      

  4.   

    for(;b.i<10;b.i++)                  
    循环最后加上Monitor.Exit(b);
    否则有死锁
      

  5.   

    楼主,请把你的思想再表达一次,现在,对你的代码,我越看越不明白,它居然可以很好的执行,没有发生异常至少。请你把Monitor的每一个方法后,加上一条注释,谢谢!
      

  6.   

    循环最后加上Monitor.Exit(b);这个方法可以哦,确实是给锁住了,现在可以了
      

  7.   

    Enter和Eixt方法是成对出现的,循环最后加上Monitor.Exit(b);这个方法可以,看来我左拚右凑的思路还是有点可行的只是本来想每个线程对每个的i进行操作,但现在是每个线程什么时候开始它就用什么时候的i我还要再改进一下才行
      

  8.   

    To 楼主,
    就目前我对你这段程序的多次调试和理解后,我认为,加上Monitor.Exit(b);也不行,程序根本就不是按照你的原意在执行,至于为什么,我也不知道,我根本没法理解你的思维,不过,我可以这样来实现它,一会给出代码。
    愿意和你谈一下,加我 QQ4896536 附言:.NET
      

  9.   

    using System;
    using System.Threading;public class T
    {
       public int chk; //互斥资源数
       public int i;   //循环层次
       public int num = 0; //线程计数,将以0为基数
       public bool blBlock = false; //用于判断有无阻塞的线程

       public T(int a,int b)
       {
          chk = a;
          i = b;
       }   public void go()
       {
          int i = 0;
          i = Interlocked.Increment( ref num ) - 1;
          Console.WriteLine("$ Running Thread-" + i +" .");
          Thread.Sleep(2000); //相当于运行一秒钟
          Console.WriteLine("# Complete Thread-" + i +" .");      if( blBlock == true )
             A.synchro.Set(); //
       }
    }public class A
    {
       static public ManualResetEvent synchro = null;   public static void Main()
       {
          T b = new T( 3, 0 ); //初始化chk=3,i=0
          
          synchro = new ManualResetEvent(false);
          //Thread MainThread = Thread.CurrentThread;

          for(b.i = 0; b.i<10; b.i++) //循环10次,产生10个线程
          {         ThreadStart myThreadDelegate = new ThreadStart(b.go);
             Thread myThread = new Thread(myThreadDelegate);          if( b.chk > 0)//判断资源数目
             {
                b.chk --;
                Console.WriteLine("* Call Thread-"+b.i+". But Not in the Thread-"+b.i+" .");
                myThread.Start(); //
             }
             else
             {
                Console.WriteLine("Not enough resoucre! Block to start Thread-"+ b.i+" !!!");
                b.blBlock = true;
                synchro.WaitOne(); //for循环被挂起,即当前线程被阻塞 
                Console.WriteLine("* Call Thread-"+b.i+". But Not in the Thread-"+b.i+" .");
                myThread.Start();
             }
          }
          Console.WriteLine("End of for-Loop");
       }
    }/* 1. 我的想法是把b.chk作为有限个互斥资源,本例中为3个
     * 2. 重写了你的for循环和go方法
     * 3. 在for循环中,资源没有时,阻塞!//该程序已经测试通过
     * */
      

  10.   

    再顶一下对于你的方法,我硬是理解不了,还望高手解释。上面我给出的方法或许不是你想要的,因为,不是同时并发十线程后,由线程来自动同步运行,其同步的代码放在了for循环中。如果你需要在线程中来同步,请说一声,我再重新贴一段。
      

  11.   

    using System;
    using System.Threading;public class T
    {
       public int chk; //互斥资源数
       public int i;   //循环层次

       public T(int a,int b)
       {
          chk = a;
          i = b;
       }   public void go()
       {
          //首先对资源进行判断与分配,这个过程必须互斥
          Monitor.Enter( chk );
          if ( chk > 0 )
          {
             chk --;
          }
          Monitor.Exit ( chk );
          //分配到资源,开始后面的执行      Console.WriteLine("$ Running Thread-" + i +" .");
          Thread.Sleep(2000); //相当于运行两秒钟
          Console.WriteLine("# Complete Thread-" + i +" .");
         
          //执行完毕,开始释放资源
          Monitor.Enter( chk );
             chk ++;
          Monitor.Exit( chk );//释放资源
          Console.WriteLine("~ Release resource from Thread-"+i+" .");
       }
    }public class A
    {
       static public ManualResetEvent synchro = null;   public static void Main()
       {
          T b = new T( 3, 0 ); //初始化chk=3,i=0
          
          for(b.i = 0; b.i<10; b.i++) //循环10次,产生10个并发线程
          {
             ThreadStart myThreadDelegate = new ThreadStart(b.go);
             Thread myThread = new Thread(myThreadDelegate);         Console.WriteLine("* Call Thread-"+b.i+". But Not in the Thread-"+b.i+" .");
             myThread.Start();
          }
          Console.WriteLine("End of for-Loop");
       }
    }/* 1. 同时并发10个go方法
     * 2. go方法自身判断资源,决定是否执行或阻塞//已经测试通过
     * *///我QQ没有收到系统消息啊,你是不是加错人了,中午12点后我一般在线上
      

  12.   

    C#Online是吧我又加了两次不行的话你加我414159022
      

  13.   

    // using System.Threading;public class Semaphore
    {
     private static int lockCount = 0;
     
     public static void Initialize(int count)
     {
      this.lockCount = count;
     }
     
     public static void Wait()
     {
      while(this.lockCount <= 0)
      {
       Thread.Sleep(18);
      }
      this.lockCount--;
     } public static void Signal()
     {
      this.lockCount++;
     }
    }
    好了,有了这个类,你就可以这样做了。Locker.Initialize(3); // 仅 3 个线程同时运行// 线程函数像这样写。
    private void ThreadFunc()
    {
     Locker.Wait();
     ...
     Locker.Signal();
    }呵呵,上面用的就是操作系统上的信号量方法。可以试一试。
      

  14.   

    下面那段写错了,应该是
    Semaphore.Initialize(3);private void ThreadFunc()
    {
     Semaphore.Wait();
     ...
     Semaphore.Signal();
    }
      

  15.   

    晕晕地, vrace,你写的这个,没用到任何系统互斥方法,你可以保证线程同步???
    当并发多个线程时,你可以保证一个Wait()方法的原子性?服了U了!如果多个线程同时对this.lockCount <= 0进行判断呢?