2016-03-03 54 views
0

如何更正每個新啓動的線程使用新計數器的代碼。當你開始一個新的線程掛起舊的,而不是繼續。線程和新計數器

感謝您的幫助。

private void button1_Click(object sender, EventArgs e) 
    { 

     thread[counter] = new Thread(goThread); 
     thread[counter].Start(); 
     counter++; 
    } 

    private void goThread() 
    { 
      kolejka[counter] = new PictureBox(); 
      kolejka[counter].Location = new Point(325, n - 150); 
      kolejka[counter].Image = threading.Properties.Resources.car; 
      kolejka[counter].Size = new Size(20, 37); 

     this.Invoke((MethodInvoker)delegate 
     { 

      this.Controls.Add(kolejka[counter]); 
     }); 


     for (int i = 0; i < 500; i++) 
     { 
      this.Invoke((MethodInvoker)delegate 
      { 
       kolejka[counter].Location = new Point(kolejka[counter].Location.X, kolejka[counter].Location.Y - 3); 
       this.Refresh(); 
      }); 
      Thread.Sleep(50); 
     } 
    } 
+3

你好,請不要污損您的文章你已採取的幫助之後。這就像在樹下遮蔽下砍樹。請允許其他未來的用戶從知識中獲益。答覆者會付出很多努力。不要把他們的寶貴時間浪費。 –

回答

3

問題是您正在增加counter變量,但它在您的線程中使用。不要這樣做。在你的情況下,爲線程提供本地信息是非常重要的,因爲你希望每個線程都可以在「自己的」計數器上工作。這可以這樣來實現:

private class ThreadInfo 
{ 
    public PictureBox Picture; 
    public int Counter; 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    kolejka[counter] = new PictureBox(); 
    kolejka[counter].Location = new Point(325, n - 150); 
    kolejka[counter].Image = threading.Properties.Resources.car; 
    kolejka[counter].Size = new Size(20, 37); 
    this.Controls.Add(kolejka[counter]); 

    ThreadInfo info = new ThreadInfo() { 
     Picture = kolejka[counter], 
     Counter = counter 
    }; 

    thread[counter] = new Thread(goThread); 
    thread[counter].Start(info); 

    counter++; 
} 

private void goThread(object state) 
{ 
    ThreadInfo info = state as ThreadInfo; 

    for (int i = 0; i < 500; i++) 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      info.Picture.Location = new Point(info.Picture.Location.X, info.Picture.Location.Y - 3); 
      this.Refresh(); 
     }); 
     Thread.Sleep(50); 
    } 
} 

這會處理按鈕事件中的所有初始化事件,並傳遞一個info類的實例。該信息類獲取線程所需的所有信息,但是它是線程本地的!

+0

感謝您對我的回答發表評論。你可以請評論,如果它已經做了他在後臺線程所做的事情嗎?我的意思是他想要在後臺線程中移動圖像。他在後臺線程上更改座標,並在UI上更改圖片位置,他應該再次返回主線程。 – Sasha

+0

嗯,我真的不知道它是否合理,因爲這是他的項目。但是在任何響應式應用程序中,你都有東西在後臺運行,並且在某些時候你需要更新UI,所以通常情況下,從後臺線程更新UI東西確實有意義。如果它在這種情況下有用,或者使用計時器可以實現同樣的事情,我不能說。 –

0

您的代碼有幾個問題。

  • 使用變量counter而不鎖定兩個線程。
  • 請勿爲此使用數組,因爲您沒有控制中的counter值。
  • 不要在gui線程之外的其他線程上創建控件。

爲此,您不需要線程。最簡單的方法是使用一個計時器。

僞:

List<Car> _myCars = new List<Car>(); 

private Form1() 
{ 
    _timer = new Timer(); 
    _timer.Interval = 50; 
    _timer.Tick += Timer_Tick; 
} 

private void Timer_Tick(object sender, EventArgs e) 
{ 
    foreach(var car in _myCars.ToArray()) 
    { 
     car.Location = new Point(car.Location.X, car.Location.Y - 3); 
     if(car.Location.Y < 0) 
      _myCars.Remove(car); 
    } 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    _myCars.Add(new Car()); 
} 
3

你的舊線不掛。問題在於你的計數器變量。它由您的線程共享。舊線程繼續在新線程的kolejka[counter]上。我想這不是你想要的。

在你goThread方法的開始,你可以這樣做:

var item = kolejka[counter]; 

然後你就可以使用項目,而不是kolejka [計數器]。然而這也不是線程安全的,但是現在你有更好的選擇。

+0

它是否使任何意見在另一個線程上創建UI元素?我的意思是在後臺線程中創建一個帶有少量屬性的PictureBox控件應該有開銷,然後返回主線程來繪製它 – Sasha

+0

在啓動/運行線程時,可能會增加'counter'變量。你應該創建一個事件來等待。 –

0

跟進彼得,你可以在螺紋的開始創建一個副本:

private void button1_Click(object sender, EventArgs e) 
{ 
    ManualResetEvent threadStartedSignal = new ManualResetEvent(false); 
    thread[counter] = new Thread(goThread); 
    thread[counter].Start(threadStartedSignal); 

    // wait for the thread to create a local reference. 
    threadStartedSignal.WaitOne(); 
    counter++; 
} 

private void goThread(object state) 
{ 
    kolejka[counter] = new PictureBox(); 
    var myPictureBox = kolejka[counter]; 

    // signal the other thread, that the counter may be changed. 
    ((ManualResetEvent)state).Set(); 

    myPictureBox .Location = new Point(325, n - 150); 
    myPictureBox .Image = threading.Properties.Resources.car; 
    myPictureBox .Size = new Size(20, 37); 

    this.Invoke((MethodInvoker)delegate 
    { 
     this.Controls.Add(myPictureBox); 
    }); 


    for (int i = 0; i < 500; i++) 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      myPictureBox.Location = new Point(myPictureBox.Location.X, myPictureBox.Location.Y - 3); 
      this.Refresh(); 
     }); 
     Thread.Sleep(50); 
    } 
}