2014-01-13 138 views
0

我有一个线程是在打开一个新的表单实例时创建的。 这个线程应该在这个表单打开时随时运行。 表单关闭后,它应该死亡。关闭表单后关闭线程?

问题是当我打开同一个窗体的新实例时,它使用相同的线程。

我在寻找正确的代码可能是某处的这个我想行......除了这是无效的:

t = new Task(Task.Factory.StartNew(() => totalDistance())); 

这里是整个代码: 方法WindowsFormClosing可能不必要的,但我没有想法。

using System; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.Data; 
    using System.Drawing; 
    using System.Linq; 
    using System.Text; 
    using System.Threading.Tasks; 
    using System.Windows.Forms; 

    namespace ITS3_Eksamen_F2014_201270810 
    { 
    public partial class DistanceForm : Form 
    { 
     Data dat; 
     private string name; 
     Task t; 
     private bool killThread; 

     public DistanceForm(Data d, string n) 
     { 
      dat = d; 
      name = n; 
      InitializeComponent(); 
      getDistance(name); 
      nameLabel.Text = name; 
      t = Task.Factory.StartNew(() => totalDistance()); 
      killThread = false; 
     } 

     private void getDistance(string name) 
     { 
      var dList = new List<Distance>(); 
      dList = dat.getDistance(name); 
      int i = 0; 
      dataGridView1.Rows.Clear(); 
      foreach (Distance dist in dList) 
      { 
       dataGridView1.Rows.Add(); 
       dataGridView1.Rows[i].Cells[0].Value = dist.getTid(); 
       dataGridView1.Rows[i].Cells[1].Value = dist.getAngivelse(); 
       dataGridView1.Rows[i].Cells[2].Value = dist.getLængde(); 
       dataGridView1.Rows[i].Cells[3].Value = dat.getFullName(dist.getInitialer()); 
       i++; 
      } 
     } 

     private void updateInitials(string initialer, int rowNumber) 
     { 
      dataGridView1.Rows[rowNumber].Cells[3].Value = dat.getFullName(initialer); 
     } 

     private void buttonAdd_Click(object sender, EventArgs e) 
     { 
      int rowNumber = dataGridView1.CurrentCell.RowIndex; 

      if (!dataGridView1.Rows[rowNumber].Cells[0].Value.ToString().Equals("") 
       && !dataGridView1.Rows[rowNumber].Cells[1].Value.ToString().Equals("") 
       && !dataGridView1.Rows[rowNumber].Cells[2].Value.ToString().Equals("") 
       && !dataGridView1.Rows[rowNumber].Cells[3].Value.ToString().Equals("")) 
      { 
       var tid = dataGridView1.Rows[rowNumber].Cells[0].Value.ToString(); 
       var længde = dataGridView1.Rows[rowNumber].Cells[1].Value.ToString(); 
       var angivelse = dataGridView1.Rows[rowNumber].Cells[2].Value.ToString(); 
       var initialer = dataGridView1.Rows[rowNumber].Cells[3].Value.ToString(); 
       dat.addDistance(name, tid, længde, angivelse, initialer); 
      } 
      else 
      { 
       MessageBox.Show("Du skal udfylde alle felter!"); 
      } 
      int currentRow = dataGridView1.CurrentCell.RowIndex; 
      string currentRowInitialer = dataGridView1.Rows[currentRow].Cells[3].Value.ToString(); 
      updateInitials(currentRowInitialer, currentRow); 
     } 

     private void buttonRemove_Click(object sender, EventArgs e) 
     { 
      int number = dataGridView1.CurrentCell.RowIndex; 
      dat.deleteDistance(name, number); 
     } 

     private void totalDistance() 
     { 
      while (killThread == false) 
      { 
       int totalDist = 0; 
       int newDist = 0; 
       var testList = dat.getDistance(name); 
       foreach (Distance dist in testList) 
       { 
        newDist = Convert.ToInt32(dist.getLængde().Replace(" km", "")); 
        totalDist = totalDist + newDist; 
       } 

       this.BeginInvoke((Action)(() => 
        { 
         textBox1.Text = Convert.ToString(totalDist) + " km"; 
        })); 
      } 
     } 

     private void WindowsFormClosing(object sender, FormClosingEventArgs e) 
     { 
      killThread = true; 
     } 
    } 
} 

在此先感谢!

+1

“一个相同形式的新实例” - >你可能想说,你再次打开*相同的Form实例*。 – BartoszKP

+1

@BartoszKP是对的。你应该知道'Tasks'正在使用'ThreadPool',并且'ThreadPool'上的线程正在被重用。对于长时间运行的任务,你应该使用'var task3 = Task.Factory.StartNew(()=> totalDistance(),TaskCreationOptions.LongRunning);'然后它将构造新的线程。 (重用线程没有任何错误..) –

+0

不错的命名空间:ITS3_Eksamen_F2014_201270810 lol –

回答

7

您可以使用此:

private Thread _thread; 

public DistanceForm() 
{ 
    InitializeComponent(); 

    _thread = new Thread(new ThreadStart(totalDistance)); 
    _thread.Start(); 
} 

public void FormClosed(object sender, EventArgs e) 
{ 
    killThread = true; 
    _thread.Join(); 
} 

而不是使用一个布尔值,我会建议ManualResetEvent的。

像:

private Thread _thread; 
private ManualResetEvent _started = new ManualResetEvent(false); 
private ManualResetEvent _terminating = new ManualResetEvent(false); 
private ManualResetEvent _terminated = new ManualResetEvent(false); 

public void InitializeComponent() 
{ 
    _thread = new Thread(() => totalDistance()); 
    _thread.Start(); 

    // wait until the thread is started. 
    _started.WaitOne(); 
} 

private void totalDistance() 
{ 
    // do some initialization stuff.. 

    // Set started. 
    _started.Set(); 
    while(!_terminating.WaitOne(0)) 
    { 
     // ... 
    } 
    _terminated.Set(); 
} 

public void FormClosed(object sender, EventArgs e) 
{ 
    // request for terminating. 
    _terminating.Set(); 
    // wait until it's terminated. 
    _terminated.WaitOne(); 
} 

started是不是在这个情况有关,但我通常使用它时,某些情况下构建withing线程(如客户等)

的例子无一例外地处理。你应该添加try/finally。

这种方式,你有关于对线程和布尔检查作业总量控制是线程

整件事可以在新的对象内包裹。 :)

+0

看起来不错! 虽然我得到了这个: 直到窗口句柄被创建,Invoke或BeginInvoke才能在控件上调用。 我正在使用您的推荐解决方案,而不是布尔值。 –

+1

我做了一个更新(构造函数),如果它仍然不起作用,请使用'Loaded'事件。 –

+0

添加了更新,你能详细说明如何使用Loaded事件吗?我对事件和线索不太擅长。 –