首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

一个很深的有关问题,多线程相关

2013-02-19 
一个很深的问题,多线程相关using Systemusing System.Collections.Genericusing System.Linqusing Syst

一个很深的问题,多线程相关
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main(string[] args)
        {
            TaskFactory taskFactory = new TaskFactory();
            Task[] t = new Task[3];
            for (int i = 0; i < 3; i++)
            {
                t[i] = taskFactory.StartNew(() => get(i.ToString()));
                Thread.Sleep(1000);              
            }
            Task.WaitAll(t);
            Console.ReadKey();
        }
        public static void get(string u)
        {
          
            Thread.Sleep(5000);
            Console.WriteLine(u);
        }    
        }
    }
}



这里的红色代码部分去掉的话输出是 3 3 3 
如果加上红色部分,可以正常输出是 0 1 2

本人水平有限,实在不能理解这是什么原因,请各位懂的朋友指导一下。
[解决办法]
并不是你加了就对了,而是碰巧刚创建的线程,在1秒内已经完成了任务,而不加sleep,因为线程是随机执行的,所以结果怪异,你要做的应该是加互斥,而不是sleep
[解决办法]
你看你定义的task[]在循环外面,而任务的开启执行结束都是需要时间的,一个任务还没执行完成,你的下一次循环又进来了,随即影响到你当前task中的执行结果这种情况在循环内部定义即可
[解决办法]
1. 既能是异步,就是不是循环的时候就会触发get方法,当get方法触发时,获取到的 i,这时i是什么值,就输出什么值。
2.加一个局部变量。


 for (int i = 0; i < 3; i++)
 {
    var it = i;
    t[i] = taskFactory.StartNew(() => get(it.ToString()));
    // Thread.Sleep(1000);
  }

其实可以从 堆栈的内存分配来看看。
1)直接使用i,在堆栈中只有一个i=多少,只有一份,每个线程取值时,就是取值时的i的值,因为给get方法的i都是同一i。
2)加了it,堆栈中就分配了 3个 it,不同的内存地址,每个线程都找到了当时给的it。
[解决办法]
这个原因与linq本身的实现方式有关 

t[i] = taskFactory.StartNew(() => get(i.ToString()));
i.ToString()  将不会及时执行  而是在linq直接运行的时候才会执行
(() => get(i.ToString()) 只是创建一个表达式  在执行的时候的时候可能已经完成了整个循环


与线程的互斥没有关系的  因为应该没有共享变量之类的  
你应该做的是吧值的构成和linq分开  就是先执行ToString() 在构建linq语句
-------------------------------------
using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Collections;
 
namespace ConsoleApplication6
{
     class Program
     {
         static void Main(string[] args)
         {
             TaskFactory taskFactory = new TaskFactory();
             Task[] t = new Task[3];
             for (int i = 0; i < 3; i++)
             {
                 string str =  i.ToString();
                 t[i] = taskFactory.StartNew(() => get(str));
                // Thread.Sleep(1000);              
             }
             Task.WaitAll(t);


             Console.ReadKey();
         }
         public static void get(string u)
         {
           
             Thread.Sleep(5000);
             Console.WriteLine(u);
         }    
         }
}

-------------------------------------------------------
可以满足你的要求 

实际原因是linq语句的实际执行时间可能会比语句构造迟一点
 


[解决办法]
这个问题是闭包造成的,三个i.ToString()实际上是同一个i
试试支持.net2.0的fastCSharp

            fastCSharp.threading.task task = new fastCSharp.threading.task(3);
            for (int i = 0; i < 3; i++) task.Add(get, i.ToString());
            task.Dispose(true);
            Console.ReadKey();

热点排行