namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 0;
            Task task = Task.Run(() => dowork(
            ref  a));           
            Console.WriteLine(a);
        }
        static void dowork(ref int a)
        {
            a = 2;
            Console.WriteLine(a);
        }
       
      
    }
    
}
为什么输出是0,2不是2,2

解决方案 »

  1.   

    int a = 0;
                Task task = Task.Run(() => dowork(
                ref  a));           
                Console.WriteLine(a);
    主线程开出task任务后,马上去执行下一句Console.WriteLine(a);不管task线程了,task自己执行自己的顺序:
    static void Main(string[] args)
            {
                1、int a = 0;
                2、Task task = Task.Run(() => dowork(
                ref  a));           
               3、 Console.WriteLine(a);
            }
            static void dowork(ref int a)
            {
                a = 2;
                4、Console.WriteLine(a);
            }
      

  2.   

    0是Main输出的;2是由Task输出的
    Task执行不阻塞主线程
    要严格控制执行顺序,需要使用信号量或者其他的同步方法
      

  3.   


    很简单,这样写代码        static void Main(string[] args)
            {
                int a = 0;
                dowork(ref  a);           
                Console.WriteLine(a);
            }
            static void dowork(ref int a)
            {
                a = 2;
                Console.WriteLine(a);
            }不要自己明明是并发多线程操作,又来问“怎么产生不并发多线程的结果”。那就是为了 Task 而 Task 地写代码,多此一举了。
      

  4.   

    namespace ConsoleApp2
    {
        class Program
        {
            static void Main(string[] args)
            {
                int a = 0;
                Task task = Task.Run(() => dowork(
                ref  a));           
                task.Wait();
                Console.WriteLine(a);
            }
            static void dowork(ref int a)
            {
                a = 2;
                Console.WriteLine(a);
            }
           
          
        }
        
    }
      

  5.   

    从线程池中分配的Task是不会阻塞主线程的(除非显示阻塞)。代码的顺序执行继续进行,也就是task执行之后 是不影响后边代码的输出,也就是“异步”了。学习它的用法:
    https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx 不仅要会用,更要知道什么情况下可以用。
      

  6.   

    你跑了一个任务,
    所以输出0或者2都是可能的。
    因为主线程和task是并发执行的。
    至于是不是要让任务执行先输出,可以wait
      

  7.   

    没有运行顺序,windows上线程的基础就是他没顺序,不然线程的就不会那么让新手为难了因为开线程简单,任何新人想开就开,但是线程同步,信号量控制,线程间通讯,上下文控制才是线程的难以让新手使用的关键否则那些基础书,也不会再线程章节3,4页纸就告诉你线程是啥,怎么开线程。然后再花30,40页纸告诉你怎么进行线程同步,线程调度,线程排程,线程间通讯了同样的代码也证明了,为啥需要上锁,为啥需要线程安全类对象的原因了,因为他无序,你无法保证他就一定向你想的那样运行
      

  8.   

    你出现0,2是只取决于上下文运行的快慢,不取决于他运行的顺序。楼上几位写wait,是同步,强制让他先运行完而如果 int a = 0;
                Task task = Task.Run(() => dowork(
                ref  a));      
               for(i=0;i<100;i++)      //你要故意让外面比线程运行的慢,那么他就是2,2
    {
    }     
                Console.WriteLine(a);
      

  9.   

    主线程不管Task,所以直接0,2    你可以加控制 Task完了再执行后续操作   task.Wait()  可以做到
      

  10.   

    随机的.并不能确定运行顺序,如果你需要先运行A,再运行B的话。
    用ContinueWith
    如果你想全部运行完再运行某个东西的话。用whenAll
      

  11.   

    这是个好问题。Task.Run开启了一个新的线程,并且,run开始任务后不阻塞主线程,主线程不管run中的任务完成与否就进行下面的任务,所以,main方法中的Console.WriteLine(a);是要先于run子线程任务的完成而执行的,此时子线程方法dowork还没有被 调用,自然a值是0,所以输出0,随后子线程执行了a = 2;这个动作,这时的a的值才变为2。
    如果要输出2,那么就需要主线程来等待子线程执行完成后再执行下面的Console.WriteLine(a),方法是task.Wait();
    这样main方法中的代码就改为如下:
                int a = 0;
                Task task = Task.Run(() => dowork( ref a));
                task.Wait();//等待任务完成再执行下面的代码,如果不加这一句,那么下面的代码将在任务完前就执行了。
                Console.WriteLine(a);总结一下就是:Task.Run 中的方法开启了新的线程,并且在主线程中不特别指定等待它完成的情况下,主线程是不会被阻塞(所以叫异步),而在task.Wait();方法明确指定主线程需要子线程完程后才执行后面代码的情况下,这时就变成了同步。
    总体来说,多线程确实是比较绕的,这源于计算机工作原理的博大精深。刚开始学习时我自己把异步、同步和同时的概念总是分不清楚。初步理解的话可以认为异步就是同时进行任务,谁也不等谁,而同步是我们没有多线程时学习的,它反而是不同时,就是后面的代码一定要等前面的代码执行完才执行。