现在在作C#小项目(winform),遇到一个多线程的问题,我的想法是:读一个文件,得到一个流,然后用多个线程把这个流保存为文件名不同的文件(在其他目录),就像复制一样。所以专门写了一个类worker,里面有用于把读到的流按照文件名保存为文件的一个方法,所以我构造了多个线程,同时访问这个类的这个方法,但每次访问文件名参数不同,我想如果这个方法是Static的,能不能让多线程同时访问(一定要并发)?(我试了,但老有问题,why??)要不想保存几个文件就要实例化几个worker类,然后各个线程再访问不同的worker实例的方法,但这样还是有问题,第2个文件保存不上!!把代码帖出来,给大家看看,帮我找一下错误,把代码中的文件名改一下就能运行了
using System;
using System.IO;
using System.Threading;
using System.Text;
class worker 
{
public  Stream s=null;
public  string sf=null; 
public  void save()
{//Monitor.Enter(this);
               bool ifok=testSave(this.s,this.sf);
               Console.WriteLine("Thread{0}进入!!!"+Thread.CurrentThread.GetHashCode());
           if(ifok)
       Console.WriteLine("保存文件成功");
         else
         Console.WriteLine("保存文件失败");
         //Monitor.Exit(this);
}
   public  bool testSave(Stream s,string saveFile)//就是把这个方法搞成static的行不??
{
     try 
       {
       FileStream FileWriteStream=new FileStream   (saveFile,FileMode.Create,FileAccess.Write);
       BufferedStream bufferedStreamW=new BufferedStream(FileWriteStream);
       BufferedStream bufferedStreamR=new BufferedStream(s);
       byte[] byteBuffer=new byte[256];
       int intByte=0;
       do{
       intByte=bufferedStreamR.Read(byteBuffer,0,256);
       bufferedStreamW.Write(byteBuffer,0,intByte);
       bufferedStreamR.Flush();
       bufferedStreamW.Flush();
      }while(intByte>0);         
       bufferedStreamW.Close();
       bufferedStreamR.Close();
      }
     catch(Exception e)
      {Console.WriteLine("---"+e.Message+"----");
       return false;
      }
      
      return true;
      }
   }
class main
{
static worker work1=null;
static worker work2=null;
public static void Main()
{
        main ma=new main();
        FileStream fs=new FileStream("c:\\Test.Html",FileMode.Open,FileAccess.Read);
       Console.WriteLine("-------------------------------------------------------------");
        work1=new worker();
       work2=new worker();
       Stream s=fs;
       Thread t1=ma.CreateThread(work1,fs,"C:\\1.txt");
       t1.Start();
       
       Thread t2=ma.CreateThread(work2,fs,"C:\\2.txt");//如果这里参数work1,work2一样行不?
                                                      //就是线程同时访问一个对象的一个方法
                                                      //我试的这样只能有一个文件被存上?
      t2.Start();
       Console.ReadLine();
}
private  Thread CreateThread(worker work,Stream s,string sf)
{
work.s=s;
work.sf=sf;
   Thread t=new Thread(new ThreadStart(work.save));
   return t;
}
}

解决方案 »

  1.   

    FileStream fs=new FileStream("c:\\Test.Html",FileMode.Open,FileAccess.Read);
    这里的fs里面会维护一个当前位置的变量。 如果多个线程并发访问它的话该变量肯定
    会乱。
    修改建议:如果文件比较小,就一次将之读入到内存缓冲中,然后每个线程都直接将
    将这个内存缓冲写入文件。
    如果文件比较大,那么在fs的读操作上加上互斥锁,然后在每个线程中维护一个
    文件当前位置的变量,每次都以绝对位置读文件。
    再说一句:你碰到的问题最直接的原因应该是第一个线程读完文件后没有将文件
    位置指针重置。
      

  2.   

    打开一个FileStream,然后把这个流循环写入目标文件列表中的文件中,要读一个字节,循环写入5个文件,再读一个字节,再写5个文件,如此,这样不需要多线程,但是达到了同时写多个文件的并发目的,而且它保证了读取文件的代码安全性,不需要维护流指针。好处多多,还有就是节省了线程间切换的时间开销、线程的内存开销。对文件仅读取了1次,而不是5次,时间少。
      

  3.   

    谢谢两位,我的问题主要是不是关于这个的,我主要的目的是:比如我要并发的向WWW发送多个webrequest申请,并且想得到它返回的流,然后把它保存为本地html文件,当然流不可能是同时到的,因此我要用多线程来并发的发送申请,保存文件可以不是并发的,我可以写个方法,然后把这个方法互斥住,但是发送webrequest一定要并发的(系统要求),因此我要写一个方法,他有一个参数就是某个www地址,我要让多线程同时访问这个方法发送webrequest,我不能互斥这个方法,因为这样就达不到并发的目的了,因此我想问,用什么样的模式最好,我可以设计一个类,它有一个方法的功能就是专门发送webrequest的,那么,怎么样让多线程并发的访问这个类的这个方法?从而完成并发的向www发送request,如果这个方法是静态的,行不?是不是我每个线程访问这个方法时都要实例化一个那个类的对象,然后每个线程访问不同实例对象的这个方法(发送request)才能达到并发的目的?但这样感觉不好,有没有什么好的模式??谢谢!!!其实一句话,就是用多线程并发的完成某个同样的功能,那么怎么设计这个功能函数才能让多线程并发的访问他
      

  4.   

    请使用lock()关键字,多线程是将work对象中使用lock()互斥使用的对象,应该是Stream对象,问题可能出现在这里了。QQ410262397
      

  5.   

    class worker 
    { public  Stream s=null;
             lock(s)
               {
    public  string sf=null; 
    public  void save()
    {//Monitor.Enter(this);
                   bool ifok=testSave(this.s,this.sf);
                   Console.WriteLine("Thread{0}进入!!!"+Thread.CurrentThread.GetHashCode());
               if(ifok)
           Console.WriteLine("保存文件成功");
             else
             Console.WriteLine("保存文件失败");
             //Monitor.Exit(this);
      }
    }
    补上的,试试管用吗,应该可以的,因为多线程中您写的:
    work1=new worker();
           work2=new worker();
           Stream s=fs;
           Thread t1=ma.CreateThread(work1,fs,"C:\\1.txt");
           t1.Start();
           
           Thread t2=ma.CreateThread(work2,fs,"C:\\2.txt");//如果这里参数work1,work2一样行不?
    使对象 s 调用的顺序与实际的不同。
      

  6.   

    我的一孔之见:如果你只是要把Strean保存到多个文件而又不要求同步的话,你只要 new 几个 File,把Stream写入到File就可以了,何必把事情搞得那么复杂?