2014-01-13 140 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事件嗎?我對事件和線索不太擅長。 –