2011-06-01 47 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