2014-06-11 94 views
0

我尝试使用Semaphore类同步三个线程(名为“1”,“2”和“3”)。他们必须在控制台中打印一个字符串,其结果是:1-> 2-> 3。这里是我的代码:与信号灯同步

class MyThread 
{ 
    public Thread Thrd; 
    static Semaphore sem = new Semaphore(1, 1); 
    static int flag = 1; 

    public MyThread(string name) 
    { 
     Thrd = new Thread(this.Run); 
     Thrd.Name = name; 
     Thrd.Start(); 
    } 

    void Run() 
    { 
     sem.WaitOne(); 
     if (Convert.ToInt32(Thrd.Name) == flag) 
     { 
      Console.WriteLine("Thread " + Thrd.Name); 
      flag++; 
     } 
     if (flag == 4) 
      flag = 1; 
     Thread.Sleep(300); 
     sem.Release(); 
    } 
} 

class SemaphoreDemo 
{ 
    static void Main() 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      MyThread mt1 = new MyThread("1"); 
      MyThread mt2 = new MyThread("2"); 
      MyThread mt3 = new MyThread("3"); 

      mt1.Thrd.Join(); 
      mt2.Thrd.Join(); 
      mt3.Thrd.Join(); 
     } 
    } 
} 

但是有时从线程#2和#3中看不到字符串。我的错误在哪里,我该如何解决这个问题?

非常感谢!

回答

2

问题是,有时线程会按顺序获取信号量,并且您没有任何重试逻辑。看看你的Run方法。

void Run() 
{ 
    sem.WaitOne(); 
    if (Convert.ToInt32(Thrd.Name) == flag) 
    { 
     Console.WriteLine("Thread " + Thrd.Name); 
     flag++; 
    } 
    if (flag == 4) 
     flag = 1; 
    Thread.Sleep(300); 
    sem.Release(); 
} 

现在,如果名为“3”的线程首先获取信号量,会发生什么? flag等于1,所以条件码不会被执行。该线程只会休眠300毫秒,然后退出。如果你想这个工作,你必须使线程重试:

void Run() 
{ 
    bool success = false; 
    while (!success) 
    { 
     sem.WaitOne(); 
     if (Convert.ToInt32(Thrd.Name) == flag) 
     { 
      Console.WriteLine("Thread " + Thrd.Name); 
      flag++; 
      success = true; 
     } 
     sem.Release(); 
     if (!success) 
     { 
      // let somebody else try 
      Thread.Sleep(300); 
     } 
    } 
} 

这将使您的示例按预期工作。

我怀疑这只是一个练习,看看线程和信号量如何工作。但是,请注意,互斥量通常比信号量更合适,最大计数为1.

还要注意,还有其他方法可以使线程顺序执行,但如果要按顺序执行线程那么你可能不需要多于一个线程。除非那些线程正在做其他事情,他们只需要进行一次排序 - 或者很少。

+0

Jim Mischel,非常感谢! – user3649515