线程中的计时器问题
本文关键字:问题 计时器 线程 | 更新日期: 2023-09-27 17:58:17
我的应用程序在三个datagridview中独立地在三个线程中从wcf服务加载数据。我在每个线程定时器中执行,每个线程定时器每秒加载一次这些数据。
我的问题是,每次我的线程go都抛出每个线程,但就像我在方法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);
}
}
}
您的锁完全没有用。当您锁定刚创建的对象时,每个锁都将有自己的标识符,并且不会相互影响。
您需要所有应该相互排除的锁才能使用相同的对象作为标识符。
System.Timers.Timer
允许您设置SynchronizingObject
,以便它将调用UI线程上的回调。当你创建计时器时,写下:
this.timerKrakow.SynchronizingObject = this;
然后将在UI线程上调用计时器的运行时间事件。这样就不需要在事件处理程序中使用锁了。
顺便说一句,您可以使用System.Windows.Forms.Timer
做同样的事情,它总是调用UI线程上的事件处理程序。
在UI线程上引发事件的缺点是它可能会阻塞用户界面。这取决于在事件处理程序中花费的时间。如果您的事件处理程序非常快速,那么这不是问题。不过,如果处理事件处理程序需要100毫秒,那么您可能不想在UI线程上进行处理。
如果您选择不在UI线程上执行此操作,则需要同步对UI的访问。计时器事件处理程序不能只修改用户界面元素。相反,你需要这样称呼它。调用,以便在UI线程上完成任何UI修改。
我强烈建议您不要使用System.Timers.Timer
。正如文件所述:
Timer组件捕获和抑制由引发的所有异常Elapsed事件的事件处理程序。此行为可能会在.NET Framework的未来版本。
换句话说,如果您的事件处理程序中有一个引发异常的错误,您永远不会知道。我建议使用System.Windows.Forms.Timer
或System.Threading.Timer
。
我不完全理解你的问题,但(除非我弄错了)计时器回调发生在ThreadPool(或GUI线程,取决于使用情况)中,所以在不同的线程中启动它们是毫无意义的。
在我看来,您是直接从另一个线程访问DataGridView。你不应该那样做。必须始终从UI线程调用UI控件。您可以使用ISynchronizeInvoke
接口将数据传递到正确的线程中。
this.dataGridViewNowyYork.Invoke(new Action(() => {
this.dataGridViewNowyYork.Rows.Add(warunki);
}), null);