线程和新计数器

本文关键字:计数器 线程 | 更新日期: 2023-09-27 18:37:19

如何更正每个新启动的线程使用新计数器的代码。在你开始一个新线程的那一刻,旧的线程挂起,而不是继续。

感谢您的帮助。

 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);
        }
    } 

线程和新计数器

问题是您正在增加 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);
    }
} 

这将执行按钮事件中的所有初始化工作,并传入信息类的实例。该信息类获取线程所需的所有信息,但要使其是线程的本地信息!

你的旧线程没有挂起。问题出在您的计数器变量中。它由您的线程共享。旧线程只是在新线程的kolejka[counter]继续。我想这不是你想要的。

在goThread方法的开头,你可以执行以下操作:

var item = kolejka[counter];

然后你可以使用item而不是kolejka[计数器]。然而,这也不是线程安全的,但比你现在好多了。

您的代码存在几个问题。

  • 您可以使用变量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());
}

跟进彼得,你可以在线程的开头创建一个副本:

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);
    }
}