2011-06-01 50 views
2

我有我的應用程序,其中三個datagridview獨立於三個線程從wcf服務加載數據。我執行每個線程計時器,每秒載入此數據。定時器在線程問題

我的問題是,每次我走線扔每個線程,但只喜歡我顯示方法timerNowyYork_Elapsed

任何想法,爲什麼出現這種情況?我鎖線程不好?

驗證碼:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 
using System.Threading; 

namespace Sprawdzanie_warunków_pogodowych 
{ 
public partial class Form1 : Form 
{ 
    PogodaEntities entity = new PogodaEntities(); 
    System.Timers.Timer timerKrakow = new System.Timers.Timer(); 
    System.Timers.Timer timerSzczecin = new System.Timers.Timer(); 
    System.Timers.Timer timerNowyYork = new System.Timers.Timer(); 
    KeyValuePair<string, string> krakowInfo; 
    KeyValuePair<string, string> szczecinInfo; 
    KeyValuePair<string, string> nowyYorkInfo; 

    public Form1() 
    { 
     System.Net.ServicePointManager.Expect100Continue = false; 
     InitializeComponent(); 
     List<MiastoContainer> miasta = (from miasto in entity.Miasta 
             select new MiastoContainer() 
            { 
             MiastoName = miasto.Nazwa, 
             Panstwo = miasto.Państwo 
            }).ToList(); 
     krakowInfo = new KeyValuePair<string, string>(miasta[0].MiastoName, miasta[0].Panstwo); 
     szczecinInfo = new KeyValuePair<string, string>(miasta[1].MiastoName, miasta[1].Panstwo); 
     nowyYorkInfo = new KeyValuePair<string, string>(miasta[2].MiastoName, miasta[2].Panstwo); 

     ParameterizedThreadStart ptsKrakow = new ParameterizedThreadStart(PobierzKrakow); 
     Thread tKrakow = new Thread(ptsKrakow); 
     tKrakow.Start(this.dataGridViewKrakow); 

     ParameterizedThreadStart ptsSzczecin = new ParameterizedThreadStart(PobierzSzczecin); 
     Thread tSzczecin = new Thread(ptsSzczecin); 
     tSzczecin.Start(this.dataGridViewSzczecin); 
    } 

    private void oAutorzeToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     new AboutBox1().Show(); 
    } 

    private void zapiszRaportToolStripMenuItem_Click(object sender, EventArgs e) 
    { 

    } 

    public void PobierzKrakow(object parameters) 
    { 
     this.timerKrakow.Elapsed += new System.Timers.ElapsedEventHandler(timerKrakow_Elapsed); 
     this.timerKrakow.Enabled = true; 
     this.timerKrakow.Interval = 1000; 
     this.timerKrakow.Start(); 
    } 

    public void PobierzSzczecin(object parameters) 
    { 
     this.timerSzczecin.Elapsed += new System.Timers.ElapsedEventHandler(timerSzczecin_Elapsed); 
     this.timerSzczecin.Enabled = true; 
     this.timerSzczecin.Interval = 1000; 
     this.timerSzczecin.Start(); 
    } 

    public void PobierzNowyYork(object parameters) 
    { 
     this.timerNowyYork.Elapsed += new System.Timers.ElapsedEventHandler(timerNowyYork_Elapsed); 
     this.timerNowyYork.Enabled = true; 
     this.timerNowyYork.Interval = 1000; 
     this.timerNowyYork.Start(); 
    } 

    void timerNowyYork_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { GlobalWeather.Weather weather = new GlobalWeather.Weather(); 
     lock (weather) 
     { 
      //thread always start from here 
      List<object> weatherList = new List<object>(); 
      weatherList.Add(weather.GetTempreature(nowyYorkInfo.Key, nowyYorkInfo.Value)); 
      //and end here , never come any line further 
      weatherList.Add(weather.GetPressure(nowyYorkInfo.Key, nowyYorkInfo.Value)); 
      weatherList.Add(weather.GetHumidity(nowyYorkInfo.Key, nowyYorkInfo.Value)); 
      weatherList.Add(weather.GetVisibility(nowyYorkInfo.Key, nowyYorkInfo.Value)); 
      entity.SaveChanges(); 

      WarunkiPogodowe warunki = new WarunkiPogodowe() 
      { 
       Temperatura = weatherList[0].ToString(), 
       Ciśnienie = weatherList[1].ToString(), 
       Wilgotność = weatherList[2].ToString(), 
       Widoczność = weatherList[3].ToString(), 
       DataSprawdzenia = DateTime.Now 
      }; 
      entity.AddToWarunkiPogodowe(warunki); 
      entity.SaveChanges(); 
      int miastoId = entity.Miasta.First(m => m.Nazwa == nowyYorkInfo.Key).id; 
      Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe() 
      { 
       idMiasto_FK = miastoId, 
       idWarunkiPogodowe_FK = warunki.id 
      }; 
      entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp); 
      entity.SaveChanges(); 

      this.dataGridViewNowyYork.Rows.Add(warunki); 
     } 
    } 

    void timerSzczecin_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     GlobalWeather.Weather weather = new GlobalWeather.Weather(); 

     lock (weather) 
     { 
      List<object> weatherList = new List<object>(); 
      weatherList.Add(weather.GetTempreature(szczecinInfo.Key, szczecinInfo.Value)); 
      weatherList.Add(weather.GetPressure(szczecinInfo.Key, szczecinInfo.Value)); 
      weatherList.Add(weather.GetHumidity(szczecinInfo.Key, szczecinInfo.Value)); 
      weatherList.Add(weather.GetVisibility(szczecinInfo.Key, szczecinInfo.Value)); 
      entity.SaveChanges(); 

      WarunkiPogodowe warunki = new WarunkiPogodowe() 
      { 
       Temperatura = weatherList[0].ToString(), 
       Ciśnienie = weatherList[1].ToString(), 
       Wilgotność = weatherList[2].ToString(), 
       Widoczność = weatherList[3].ToString(), 
       DataSprawdzenia = DateTime.Now 
      }; 
      entity.AddToWarunkiPogodowe(warunki); 
      entity.SaveChanges(); 
      int miastoId = entity.Miasta.First(m => m.Nazwa == szczecinInfo.Key).id; 
      Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe() 
      { 
       idMiasto_FK = miastoId, 
       idWarunkiPogodowe_FK = warunki.id 
      }; 
      entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp); 
      entity.SaveChanges(); 

      this.dataGridViewSzczecin.Rows.Add(warunki); 
     } 
    } 
    void timerKrakow_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     GlobalWeather.Weather weather = new GlobalWeather.Weather(); 

     lock (weather) 
     { 
      List<object> weatherList = new List<object>(); 
      weatherList.Add(weather.GetTempreature(krakowInfo.Key, krakowInfo.Value)); 
      weatherList.Add(weather.GetPressure(krakowInfo.Key, krakowInfo.Value)); 
      weatherList.Add(weather.GetHumidity(krakowInfo.Key, krakowInfo.Value)); 
      weatherList.Add(weather.GetVisibility(krakowInfo.Key, krakowInfo.Value)); 
      entity.SaveChanges(); 

      WarunkiPogodowe warunki = new WarunkiPogodowe() 
      { 
       Temperatura = weatherList[0].ToString(), 
       Ciśnienie = weatherList[1].ToString(), 
       Wilgotność = weatherList[2].ToString(), 
       Widoczność = weatherList[3].ToString(), 
       DataSprawdzenia = DateTime.Now 
      }; 
      entity.AddToWarunkiPogodowe(warunki); 
      entity.SaveChanges(); 
      int miastoId = entity.Miasta.First(m => m.Nazwa == krakowInfo.Key).id; 
      Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe() 
      { 
       idMiasto_FK = miastoId, 
       idWarunkiPogodowe_FK = warunki.id 
      }; 
      entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp); 
      entity.SaveChanges(); 

      this.dataGridViewKrakow.Rows.Add(warunki); 
     } 
    } 
} 

class MiastoContainer 
{ 
    string miastoName; 

    public string MiastoName 
    { 
     get { return miastoName; } 
     set { miastoName = value; } 
    } 
    string panstwo; 

    public string Panstwo 
    { 
     get { return panstwo; } 
     set { panstwo = value; } 
    } 

    public MiastoContainer() 
    { } 

    public MiastoContainer(string miasto, string panstwo) 
    { 
     this.MiastoName = miasto; 
     this.Panstwo = panstwo; 
    } 

    public void Add(MiastoContainer item) 
    { 
     ((ICollection<MiastoContainer>)this).Add(item); 
    } 

} 

}

回答

2

你的鎖完全沒用。當您鎖定剛剛創建的對象時,每個鎖都將擁有自己的標識符,並且完全不會相互影響。

您需要所有鎖應該排除對方使用相同的對象作爲標識符。

+0

那麼如何強制每個線程執行他的工作在計時器同步? – netmajor 2011-06-02 07:04:32

+0

以下面的形式創建一個新變量:'object sync = new object();'並將其用於鎖。 – Guffa 2011-06-02 08:46:41

+0

並傳入此對象在線程中使用的所有內容都不屬於線程? – netmajor 2011-06-02 09:46:20

0

我不完全明白你的問題,但(除非我錯了)的計時器回調發生在線程池(或GUI線程,依賴在使用上),所以在不同的線程中啓動它們毫無意義。

+0

在這種情況下,當他們嘗試訪問由UI線程創建的控件時,這些回調將引發異常(跨線程操作無效)...像datagridview – DarkSquirrel42 2011-06-02 00:07:26

0

在我看來,你是直接從另一個線程訪問DataGridView。你不應該那樣做。 UI控件必須始終從UI線程中調用。您可以使用ISynchronizeInvoke接口將數據傳遞到正確的線程。

this.dataGridViewNowyYork.Invoke(new Action(() => { 
    this.dataGridViewNowyYork.Rows.Add(warunki); 
}), null); 
+0

我應該使用此代碼,而不是this.dataGridViewNowyYork.Rows.Add(warunki); ? – netmajor 2011-06-02 07:00:33

2

System.Timers.Timer允許您設置SynchronizingObject,這樣它會調用UI線程回調。創建定時器時,請寫:

this.timerKrakow.SynchronizingObject = this; 

然後在UI線程上調用計時器的已過時事件。這消除了在事件處理程序中鎖定的需要。

順便說一句,您可以使用一個System.Windows.Forms.Timer來做同樣的事情,它總是調用UI線程上的事件處理函數。

在UI線程上引發事件的缺點是可能會阻塞用戶界面。這取決於在事件處理程序中花費了多少時間。如果您的事件處理程序非常快,那麼這不是問題。但是,如果處理事件處理程序需要100毫秒的時間,那麼您可能不想在UI線程上執行它。

如果您選擇不在UI線程上執行此操作,則需要同步對UI的訪問。定時器事件處理程序不能只修改用戶界面元素。相反,您需要調用this.Invoke,以便在UI線程上完成任何UI修改。我建議你不要使用System.Timers.Timer。由於documentation狀態:

定時器組件捕獲並 抑制由 事件處理經過的事件引發的所有異常。 此行爲在未來版本的.NET Framework中可能會發生更改 。

換句話說,如果您的事件處理程序中有一個引發異常的錯誤,您將永遠不會知道它。我建議改用System.Windows.Forms.TimerSystem.Threading.Timer