计时器的想法与线程C#窗口形式

时间:2015-10-09 06:42:14

标签: c# multithreading timer thread-safety

我的项目有一个MainForm,我显示F_Insert并为MainForm设置MdiParent

F_Insert f = new F_Insert();
f.MdiParent = this;  
f.Show();

在F_Insert中,我按下了一个像这样的CLick事件的按钮

 private void btn_Add_Click(object sender, EventArgs e)
 {
       //Insert data to SQL
 }

此外,我想自动上传每隔5秒从F_Insert插入的数据

我使用System.Timer.Timer并将其设置为MainForm_Load中的Thread

Thread t1 = new Thread(new ThreadStart(Timerss)); //In MainFormLoad event
t1.Start(); 

public void Timerss()
    {
        System.Timers.Timer timer = new System.Timers.Timer(5000);
        timer.Elapsed += Timer_Insert_Tick;
        timer.AutoReset = true;
        timer.Start();
    }

private static void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
    {
      //code auto upload data to server here
      //Data get from Sql Local to upload SQL in Server
    }

问题是它不能正常工作。我觉得当我从F_Insert插入数据时,数据会受到我在MainForm加载中启动的Timerss线程的影响。

  

向您展示我的问题的简单方法:当我拆分两个工作时(插入   并上传到2个不同的工作,它运作良好,它的意思是我   插入数据完成然后,我上传数据,它将工作良好。   但是当我在同一时间插入数据和数据自动上传时,   我看到一些错误:连接sql关闭或打开错误,没有数据获取   来自F_Insert,有时它会获得重复数据(旧数据)

请为我提出这个问题的一些想法。对不起,但我是新手。谢谢!!!

1 个答案:

答案 0 :(得分:0)

根据你想要做的事情,这段代码应该被修改,但我希望它能给你起点。

首先让我们创建静态字段:

static volatile bool isDataChanged;

关键字volatile使这个bool线程安全,这意味着当多线程环境中的任何线程访问该字段时,该字段始终保持最新(因此正确)值。

我们需要此字段来保存稍后用于检查数据是否被修改的bool值。

假设在click事件处理程序中修改了数据,我们应该将此标志设置为true:

 private void btn_Add_Click(object sender, EventArgs e)
 {
       // Data is modified in UI thread

       isDataChanged = true;
 }

然后我们假设在Timer tick事件中我们应该将最新数据上传到数据库(数据位于UI线程中,并且可能在两个tick事件之间的时间跨度上发生变化)。

首先,我们检查我们的数据是否有任何变化,如果不存在,我们只退出该方法。如果进行了更改,我们需要将它们上传到DB,为了做到这一点,我们必须处理这样一个事实,即Timer线程中的数据很可能与我们的UI线程中的数据不同。

让我们创建一个局部变量来保存我们从UI线程获取的正确数据,并使用this.Invoke()在UI线程上调用Func<object>委托。附加到委托的方法将从UI线程检索的正确数据的实例返回为object。我们将它明确地转换为我们的数据类型(通常是List<T>Dictionary<T1, T2>之类的集合类型之一)并使用此数据将其上传到数据库。

之后,因为我们在数据库中的数据是正确的,我们将标记isDataChanged更改为false

private void Timer_Insert_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
   if(!isDataChanged) return;

   // A very important line. It gets data from UI thread before uploading it
   // Change DataType with your data Type and dataToUpload with data instance

   DataType data = (DataType)this.Invoke(new Func<object>(() => dataToUpload));

   //use data to upload your data to server

   isDataChanged = false;
}

P.S。 最好在外部作用域中放置对Timer的引用(因此可以从表单内的任何地方访问它)

public partial class MyForm : Form
{
   ...
   System.Timers.Timer timer; 

   public void Timerss()
   {
      timer = new System.Timers.Timer(5000); 
   }

   ...
}