线程和新计数器

时间:2016-03-03 09:30:38

标签: c# multithreading counter

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

感谢您的帮助。

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

4 个答案:

答案 0 :(得分:3)

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

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

var item = kolejka[counter];

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

答案 1 :(得分: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类的实例。该信息类获取线程需要的所有信息,但它是线程的本地信息!

答案 2 :(得分: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 :(得分:0)

跟进 Peter ,你可以在帖子的开头创建一个副本:

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