2013-05-16 255 views
0

好的夥計們,因爲我是多線程新手而不想留下任何東西,所以會在這裏放下很多代碼來解決這個問題。BackGroundWorker一次只允許兩個線程

問題:我有一個用戶控件,我從供應商處下載數據供稿文件。我希望能夠一次處理這幾個,但是,我設置BackGroundWorker的方式,它一次只能運行兩次下載,而其他人似乎「排隊等候」一個其他兩項在開始前完成。那些正在等待的人,使其到達FTPDownload()中的第一個「GetResponse」調用。

如果我取消當前正在運行的任何一個下載,那麼「等待中」的下載永遠不會啓動。

我在DoWork事件中使用狀態來讓它決定要啓動哪個進程,並且在WorkComplete事件中讀取相同的狀態以決定如何結束進程。

一切工作正常,除了我所描述的。

代碼:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Data; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using GooeyPC_CCSE; 
using System.Text.RegularExpressions; 
using System.IO; 
using System.Net; 

namespace Gooey_Manager 
{ 
    public partial class DFProgressControl : UserControl 
    { 
     BackgroundWorker _bg_worker = new BackgroundWorker(); 

     #region Private Members and Public Accessors 
     /// <summary> 
     /// Get/Set DFProgressControl Vendor Name 
     /// </summary> 
     public string VendorName 
     { 
      get { return lblDFP_VendorName.Text; } 
      set { lblDFP_VendorName.Text = value; } 
     } 

     /// <summary> 
     /// Get/Set DFProgressControl CurrentState 
     /// </summary> 
     public string CurrentState 
     { 
      get { return lblDFP_CurrentState.Text; } 
      set { lblDFP_CurrentState.Text = value; } 
     } 

     /// <summary> 
     /// Get/Set DFProgressControl RecordOfNum 
     /// </summary> 
     public string RecordOfNum 
     { 
      get { return lblDFP_RecordOfNum.Text; } 
      set { lblDFP_RecordOfNum.Text = value; } 
     } 

     private AffiliateServiceProviderItem _aff_svc_prov = new AffiliateServiceProviderItem(); 
     public AffiliateServiceProviderItem AffiliateSvcProvider 
     { 
      get { return _aff_svc_prov; } 
      set { _aff_svc_prov = value; } 
     } 

     private VendorSiteInfoItem _vsi = new VendorSiteInfoItem(); 
     public VendorSiteInfoItem VendorSiteInfo 
     { 
      get { return _vsi; } 
      set { _vsi = value; } 
     } 

     /// <summary> 
     /// DataFeeder States 
     /// </summary> 
     public enum ObjectState 
     { 
      Nothing = 0, 
      Canceling = 1, 
      Download = 2, 
      Unzip = 3, 
      Prestage = 4, 
      Validate = 5, 
      Move_to_DB = 6, 
      Destroy = 7 
     } 
     private ObjectState _feeder_state = ObjectState.Nothing; 
     public ObjectState FeederState 
     { 
      get { return _feeder_state; } 
      set { _feeder_state = value; } 
     } 
     #endregion 

     /// <summary> 
     /// Constructor 
     /// </summary> 
     /// <param name="vendor_id"></param> 
     public DFProgressControl(int vendor_id) 
     { 
      InitializeComponent(); 

      //Initialize member data 
      this._vsi = GooeyDataFactory.GetVendorSiteInfo(vendor_id); 
      this._aff_svc_prov = GooeyDataFactory.GetAffiliatSvcProviderByID(_vsi.AffiliateSvcProviderID); 
      VendorName = _vsi.SiteName; 
      CurrentState = FeederState.ToString(); 
      RecordOfNum = ""; 

      //Background worker settings 
      _bg_worker.WorkerSupportsCancellation = true; 

      //Background worker event handlers 
      _bg_worker.DoWork += new DoWorkEventHandler(workerDataFeeder_DoWork); 
      _bg_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerDataFeeder_RunWorkerCompleted); 
     } 

     private void workerDataFeeder_DoWork(object sender, DoWorkEventArgs e) 
     { 
      switch (FeederState) 
      { 
       case ObjectState.Download: 
        this.ProductDataFeedDownload(VendorName); 
        break; 
       case ObjectState.Unzip: 
        break; 
       default: 
        break; 
      } 
     } 

     private void workerDataFeeder_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      switch (FeederState) 
      { 
       case ObjectState.Download: 
        lblDFP_RecordOfNum.Text = "Download Complete"; 
        FeederState = ObjectState.Nothing; 
        break; 
       case ObjectState.Unzip: 
        FeederState = ObjectState.Nothing; 
        break; 
       case ObjectState.Canceling: 
        lblDFP_RecordOfNum.Text = "Operation Canceled"; 
        pbDFP_ProgressBar.Value = 0; 
        FeederState = ObjectState.Nothing; 
        break; 
       default: 
        break; 
      } 
      CurrentState = FeederState.ToString(); 
     } 

     ///////////////////////////////////////////////////////////////////////////////////////////////////// 
     //Data Feeder Process menu items 
     ///////////////////////////////////////////////////////////////////////////////////////////////////// 

     /// <summary> 
     /// Download vendor's data feed file 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void downloadToolStripMenuItem_Click(object sender, EventArgs e) 
     { 
      if (_bg_worker.IsBusy) 
      { 
       MessageBox.Show(VendorName + " Data Feeder is busy with " + CurrentState + "\nCancel Operation to do something else."); 
      } 
      else 
      { 
       FeederState = ObjectState.Download; 
       CurrentState = FeederState.ToString(); 
       lblDFP_RecordOfNum.Text = "Preparing to download..."; 
       pbDFP_ProgressBar.Value = 0; 
       _bg_worker.RunWorkerAsync(); 
      } 
     } 

     /// <summary> 
     /// Cancel current operation 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void cancelOperationToolStripMenuItem_Click(object sender, EventArgs e) 
     { 
      if (_bg_worker.IsBusy) 
      { 
       FeederState = ObjectState.Canceling; 
      } 
      else 
      { 
       MessageBox.Show("No operation to stop for " + VendorName + " data feeder."); 
      } 
     } 

     private void destroyToolStripMenuItem_Click(object sender, EventArgs e) 
     { 

     } 

     ///////////////////////////////////////////////////////////////////////////////////////////////////// 
     //Data Feed Stuff 
     ///////////////////////////////////////////////////////////////////////////////////////////////////// 

     /// <summary> 
     /// Download Vendor's data feed 
     /// </summary> 
     /// <param name="vendor_name"></param> 
     /// <param name="pb"></param> 
     /// <param name="status_text"></param> 
     /// <returns></returns> 
     public byte[] ProductDataFeedDownload(string vendor_name) 
     { 
      string filename = Regex.Match(this._vsi.DFFTPProd, @"(\w|[-.])+$", RegexOptions.IgnoreCase).ToString(); 
      byte[] data_feed = FTPDownload(this._vsi.DFFTPProd, this._aff_svc_prov.FTPUser, this._aff_svc_prov.FTPPassword); 

      if (data_feed.Length != 0) 
      { 
       //Write the bytes to a file 
       //NOTE: Do I really need to be Using Windows.Forms for this. System.IO should have the necessary methods? 
       SaveFileDialog save_data_feed = new SaveFileDialog(); 
       save_data_feed.FileName = this._vsi.DFFileTextProd + "\\" + filename; 
       FileStream newFile = new FileStream(save_data_feed.FileName, FileMode.Create); 
       newFile.Write(data_feed, 0, data_feed.Length); 
       newFile.Close(); 
      } 
      return data_feed; 
     } 

     /// <summary> 
     /// Connects to the FTP server and downloads the file 
     /// </summary> 
     /// <param name="FTPAddress"></param> 
     /// <param name="username"></param> 
     /// <param name="password"></param> 
     /// <param name="pb"></param> 
     /// <param name="status_text"></param> 
     /// <returns></returns> 
     private byte[] FTPDownload(string FTPAddress, string username, string password) 
     { 
      byte[] downloadedData = new byte[0]; 

      try 
      { 
       //Create FTP request 
       //Note: format is ftp://server.com/file.ext 
       FtpWebRequest request = FtpWebRequest.Create(FTPAddress) as FtpWebRequest; 

       //Get the file size first (for progress bar) 
       request.Method = WebRequestMethods.Ftp.GetFileSize; 
       request.Credentials = new NetworkCredential(username, password); 
       request.UsePassive = true; 
       request.UseBinary = true; 
       request.KeepAlive = true; //don't close the connection 
       int dataLength = 999999; 
       dataLength = (int)request.GetResponse().ContentLength;//This does not work for Tigerdirect download. Causes error.     

       //Now get the actual data 
       request = FtpWebRequest.Create(FTPAddress) as FtpWebRequest; 
       request.Method = WebRequestMethods.Ftp.DownloadFile; 
       request.Credentials = new NetworkCredential(username, password); 
       request.UsePassive = true; 
       request.UseBinary = true; 
       request.KeepAlive = false; //close the connection when done 

       //Streams 
       FtpWebResponse response = request.GetResponse() as FtpWebResponse; 
       Stream reader = response.GetResponseStream(); 

       //Download to memory 
       MemoryStream memStream = new MemoryStream(); 
       byte[] buffer = new byte[1024]; //downloads in chuncks 
       decimal bytesDownloaded = 0; 
       bool cancel = false; 
       while (!cancel) 
       { 
        //Try to read the data 
        int bytesRead = reader.Read(buffer, 0, buffer.Length); 

        if (bytesRead == 0) 
        { 
         break; 
        } 
        else 
        { 
         //Write the downloaded data 
         memStream.Write(buffer, 0, bytesRead); 
         bytesDownloaded += bytesRead; 

         //Show Progress 
         ShowProgress(bytesRead, dataLength); 

         //Check for cancelation request 
         if (this.FeederState == ObjectState.Canceling) 
         { 
          DialogResult result = MessageBox.Show("Click OK to stop current operation for " + VendorName + " data feeder.", "Cancel?", MessageBoxButtons.YesNo); 
          if (result == DialogResult.Yes) 
          { 
           _bg_worker.CancelAsync(); 
           cancel = true; 
           memStream = null; 
          } 
          else 
          { 
           this.FeederState = ObjectState.Download; 
          } 
         } 
        } 
       } 

       //Convert the downloaded stream to a byte array 
       if (memStream != null) 
       { 
        downloadedData = memStream.ToArray(); 
        memStream.Close(); 
       } 

       //Clean up 
       reader.Close(); 
       response.Close(); 
      } 
      catch (Exception e) 
      { 
      } 

      username = string.Empty; 
      password = string.Empty; 
      return downloadedData; 
     } 

     /// <summary> 
     /// Update progress bar and Record of Num values 
     /// </summary> 
     /// <param name="progress"></param> 
     /// <param name="upper_bound"></param> 
     private void ShowProgress(int progress, int upper_bound) 
     { 
      //Current State 
      lblDFP_CurrentState.Invoke((MethodInvoker)delegate 
      { 
       lblDFP_CurrentState.Text = this.FeederState.ToString(); 
      }); 

      //Current Progress 
      pbDFP_ProgressBar.Invoke((MethodInvoker)delegate 
      { 
       pbDFP_ProgressBar.Maximum = upper_bound; 
       if (pbDFP_ProgressBar.Value + progress < upper_bound) 
       { 
        pbDFP_ProgressBar.Value += progress; 
       } 
       else 
       { 
        pbDFP_ProgressBar.Value = upper_bound; 
       } 
      }); 

      //Current value of progress over upper bound 
      lblDFP_RecordOfNum.Invoke((MethodInvoker)delegate 
      { 
       lblDFP_RecordOfNum.Text = (Convert.ToDecimal(pbDFP_ProgressBar.Value)/1024/1024).ToString("0.00") + " of " + (Convert.ToDecimal(upper_bound)/1024/1024).ToString("0.00") + " MB read."; 
      }); 
     } 
    } 
} 

我敢肯定,我失去了一些東西基本在這裏,我希望有人能賜教。就像我說的,對於線程化的東西來說很新穎 - 雖然我很高興,但我知道了這一點;它沒有按照我的意圖工作。

在此先感謝。

編輯: 我還要補充我如何實例化用戶控件

//Data Feed Tab 
private void btnStartDataFeed_Click(object sender, EventArgs e) 
{ 
    DFProgressControl _df_prog_ctl = new DFProgressControl((int)lbDataFeedVendorList.SelectedValue); 
    if (_df_control_list.Find(o => o.VendorSiteInfo.VendorSiteInfoID == (int)lbDataFeedVendorList.SelectedValue) == null) 
    { 
     //Add instance of object to Data Feeder list 
     flowLayoutPanel1.Controls.Add(_df_prog_ctl); 
     _df_control_list.Add(_df_prog_ctl); 
    } 
    else 
    { 
     MessageBox.Show("There is already an active data feeder for " + GooeyDataFactory.GetVendorSiteInfo(_df_prog_ctl.VendorSiteInfo.VendorSiteInfoID).SiteName + " doing " + _df_prog_ctl.FeederState + "."); 
    } 
} 
+0

它只是想到,也許聯屬機構的源只允許從同一個IP的兩個活動下載。 –

回答

1

的後臺工作是否正常工作。問題是源只允許兩個活動下載從同一個IP同時運行。

無論如何。

+0

,這不是一個答案!你可以評論:) – zey

+0

@zey在哪些方面不是答案? –