首页 新闻 赞助 找找看

C#多线程问题,请大神不吝赐教。

0
悬赏园豆:50 [已解决问题] 解决于 2016-03-31 15:13

小弟接触线程不多,今天试着写个程序,三个线程,每个线程分别打印A,B,C三个字母 7次,最后执行结果为:ABCABCABC........

代码:

 1   class Program
 2     {
 3         int  count = 1;
 4         AutoResetEvent areA = new AutoResetEvent(false);
 5         AutoResetEvent areB = new AutoResetEvent(false);
 6         AutoResetEvent areC = new AutoResetEvent(false);
 7         object lockme = new object();
 8 
 9         static void Main(string[] args)
10         {
11             Program program = new Program();
12             Thread A = new Thread(program.PrintA);
13             Thread B = new Thread(program.PrintB);
14             Thread C = new Thread(program.PrintC);
15 
16             A.Name = "A";
17             B.Name = "B";
18             C.Name = "C";
19 
20             A.Start();
21             Thread.Sleep(100);
22             B.Start();
23             Thread.Sleep(100);
24             C.Start();
25             //D.Start();
26             Console.WriteLine("主线程执行结束");
27             Console.ReadKey();
28         }
29 
30         private void PrintC()
31         {
32             for (int i = 0; i <= 19; i++)
33             {
34                 Thread.Sleep(100);
35                 //lock (lockme)
36                 //{
37                     if (count % 3 == 0)
38                     {
39                         Console.WriteLine("C");
40                         count++;
41                         areC.Set();
42                     }
43                     else if (count % 3 == 1)
44                     {
45                         areA.WaitOne();
46                     }
47                 //}
48             }
49         }
50 
51         private void PrintB()
52         {
53             for (int i = 0; i <= 19; i++)
54             {
55                 Thread.Sleep(100);
56                 //lock (lockme)
57                 //{
58                     if (count % 3 == 2)/*当前线程可打印*/
59                     {
60                         Console.WriteLine("B");
61                         count++;
62                         areB.Set();
63                     }
64                     else if (count % 3 == 0)
65                     {
66                         areC.WaitOne();
67                     }
68                 //}
69             }
70         }
71 
72         private void PrintA()
73         {
74             for (int i = 0; i <= 19; i++)
75             {
76                 Thread.Sleep(100);
77                 //lock (lockme)
78                 //{
79                     if (count % 3 == 1) /*当前线程可打印*/
80                     {
81                         Console.WriteLine("A");
82                         count++;
83                         areA.Set();
84                     }
85                     else if (count % 3 == 2)
86                     {
87                         areB.WaitOne();
88                     }
89                 //}
90             }
91         }
92     }

问题1:加上lock锁后(代码中注释掉部分),执行结果如下:

三个线程对count进行读写操作,这里加上lock应该是合理的,为什么执行结果不正确呢?

 

问题2:去除程序中34,55,76行中的Thread.Sleep(100);程序结果如下:

为什么会加上Thread.Sleep(100);这一句呢?因为在调试的时候在32,53,74行加入断点,单步执行后程序正常输出ABCABC...,直接执行就是以上结果。这是为什么呢?

三当家的主页 三当家 | 菜鸟二级 | 园豆:383
提问于:2016-03-31 11:16
< >
分享
最佳答案
1

因为线程执行的时候是任务抢占式执行,谁抢到当前时间片谁就执行,所以就不会输出正确代码了,但是你加上sleep以后,导致当前线程因为挂起不再抢占了……所以你 歪打正着输出了正确答案,但是你的思路有问题,我把正确代码给你贴出来如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication9
{
    class Program
    {
       public static AutoResetEvent flag1 = new AutoResetEvent(false);
       public static AutoResetEvent flag2 = new AutoResetEvent(false);
       public static AutoResetEvent flag3 = new AutoResetEvent(false);
        static void Main(string[] args)
        {


            Thread th1 = new Thread(new ThreadStart(A));
            Thread th2 = new Thread(new ThreadStart(B));
            Thread th3 = new Thread(new ThreadStart(C));
            th1.Start();
            th2.Start();
            th3.Start();
        }

        static void A()
        {
            flag1.Set();
            for (int i = 0; i < 7; i++)
            {
                flag1.WaitOne();
                Console.WriteLine("A");
                flag2.Set();
            }
        }
        static void B()
        {
            for (int i = 0; i < 7; i++)
            {
                flag2.WaitOne();
                Console.WriteLine("B");
                flag3.Set();
            }
        }
        static void C()
        {
            for (int i = 0; i < 7; i++)
            {
                flag3.WaitOne();
                Console.WriteLine("C");
                flag1.Set();
            }
        }
    }
}

 

收获园豆:50
需要格局 | 老鸟四级 |园豆:2145 | 2016-03-31 13:07

思路确实有问题,每个线程多次执行WaitOne,很容易死锁。程序执行混乱,可读性不好。通过您的答案,提高了小弟对同步事件的理解,谢谢!

三当家 | 园豆:383 (菜鸟二级) | 2016-03-31 15:11
其他回答(3)
1

 

你这不是在写代码,你这是在编绕口令。

Launcher | 园豆:45045 (高人七级) | 2016-03-31 11:23

最近研究多线程,这些是测试代码,对于问题1、2,请教大神帮忙解惑。

支持(0) 反对(0) 三当家 | 园豆:383 (菜鸟二级) | 2016-03-31 11:32

@三当家: 我们先说问题1,既然你在问“为什么执行结果不正确”,那么请告知“正确的执行结果”是什么?

支持(0) 反对(0) Launcher | 园豆:45045 (高人七级) | 2016-03-31 11:41

@Launcher: 正确的输出:ABCABCABCABC....

支持(0) 反对(0) 三当家 | 园豆:383 (菜鸟二级) | 2016-03-31 12:40

@三当家: 根据你写的代码,请讲一下为什么正确的输出是“ABCABCABCABC”?

支持(0) 反对(0) Launcher | 园豆:45045 (高人七级) | 2016-03-31 13:00

@三当家: 三个线程分别打印abc,你怎么想输出abcabcabc...这是什么需求?单核cpu可以满你,1楼的答案也不能说一定满足的。

支持(0) 反对(0) gw2010 | 园豆:1487 (小虾三级) | 2016-04-01 16:39
0

Timer(TimerCallback callback, object state, int dueTime, int period);

ThreadPool.QueueUserWorkItem()

具体用法自己在百度一下

心怀宇宙 | 园豆:643 (小虾三级) | 2016-03-31 11:33
0

我认为本质是楼没有理解到线程的用法,我很少用AutoResetEvent这种,这个应该就是平时说的pv操作吧。你打印里面的count%就是有问题的,count是多个线程的临界资源,只要处理lock count的地方就可以了。你开多个线程不是为了一起处理吗?还是这样一个p,一个v,有什么意思。

gw2010 | 园豆:1487 (小虾三级) | 2016-04-01 16:37

代码思路确实有问题,lock count只能保证临界资源的安全,但不能协调多个线程之间的执行。比如ab两个线程,当a线程的任务执行了75%的时候,需要等待b线程的任务执行完毕才能执行,此时就需要同步事件来协调两个线程之间的执行。

"三个线程分别打印abc,你怎么想输出abcabcabc...这是什么需求?单核cpu可以满你,1楼的答案也不能说一定满足的。"

这个需求只是用来熟悉多线程,听说(也只是听说)是迅雷早前的面试题。其实也可以应用到很多场景,比如流水线上的多个工序,可以同时运行,期间可能需要某个工序停止等待其它工序完成.......最后按照业务规则组装为成品。

多线程的启动顺序确实不能保证,但可以控制多线程的执行。通常并不是在一个线程开始时就阻塞其运行,这和把多个任务放到一个线程里执行的效果一样,属于在工作线程内串行执行。而1楼的答案协调了线程的执行,多核cpu下仍然是稳定的。

支持(0) 反对(0) 三当家 | 园豆:383 (菜鸟二级) | 2016-04-05 10:44

@三当家: 流水线,流水线都是一条对应一条线上,不会这样设计的。可以三条三并行,但是不会有关系,不然就不叫流水线了。然后你说的稳定只是表面的稳定,也可以说是稳定吧,但是从思想上来说完全是以你这几个线程的先后顺序来决定的,根本不是真正的控制。

支持(0) 反对(0) gw2010 | 园豆:1487 (小虾三级) | 2016-04-05 11:55

@gw2010: 线程的先后顺序?是指执行顺序还是启动顺序?启动顺序确实控制不了,但是执行是可以控制的。

支持(0) 反对(0) 三当家 | 园豆:383 (菜鸟二级) | 2016-04-05 14:22
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册