线程中的计时器问题

本文关键字:问题 计时器 线程 | 更新日期: 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.TimerSystem.Threading.Timer

我不完全理解你的问题,但(除非我弄错了)计时器回调发生在ThreadPool(或GUI线程,取决于使用情况)中,所以在不同的线程中启动它们是毫无意义的。

在我看来,您是直接从另一个线程访问DataGridView。你不应该那样做。必须始终从UI线程调用UI控件。您可以使用ISynchronizeInvoke接口将数据传递到正确的线程中。

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