1

现在,它输出 00,而不是 54。我正在学习线程,我卡在这里,我不知道现在该怎么办

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        Point[] array = new Point[20];
        public Form1()
        {
            for (int i = 0; i < 20; i++)
            {
                array[i] = new Point(); // I'm creating objects here
            }
            InitializeComponent();
        }

        void function1()
        {
            array[0].x = 5;
            array[0].y = 4;
        }

        void function2()
        {
            label1.Text = array[0].ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(function1);
            thread1.Start();
            Thread.Sleep(500);
            function2();
        }
    }

    class Point
    {
        public int x;
        public int y;
        public override string ToString()
        {
            return x.ToString() + y.ToString();
        }
    }  
}

当我这样做时(没有另一个线程)

private void Form1_Load(object sender, EventArgs e)
{
    function1();
    function2();
}

它工作正常,输出为 54 谢谢

4

4 回答 4

2

你在做什么没有多大意义。您正在启动一个线程,然后休眠 500 毫秒,然后调用使用该线程结果的函数。

这意味着您的两个操作是顺序相关的,不能并行执行。在这里使用线程是没有意义的。

您没有看到更改的原因可能是因为thread1在睡眠结束并被调用之前没有足够的时间来启动和执行其代码function2。尝试thread1.Join()改用,但就像我说的,这根本没有意义!

于 2012-04-19T10:28:15.307 回答
2

实际上,您的程序按预期在我的计算机上运行。那么为什么它不能在您的计算机上工作(或仅在某些时候工作)?这是因为您的程序中存在竞争条件。这意味着您的程序假定第二个线程(执行 function1)将在不到 500 毫秒的时间内为数组分配新值。永远不要对另一个线程完成它的任务需要多长时间做出任何假设。操作系统可以自由选择单个线程执行的时间、频率和时长,以及何时暂停它们。相反,使用同步原语(例如ManualResetEvent)来确保第二个线程已经完成了它的任务。

此代码显示,如何更改程序正确执行线程同步:

    ManualResetEvent MRE = new ManualResetEvent(false);//Add this field to Form1

    void function1()
    {
        array[0].x = 5;
        array[0].y = 4;
        MRE.Set();//This notifies first thread, that values are set.
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Thread thread1 = new Thread(function1);
        thread1.Start();
        MRE.WaitOne();//This makes this thread wait until the second thread calls MRE.Set()
        function2();
    }
于 2012-04-19T11:07:30.520 回答
1

如果function2取决于完成,function1那么您需要确保在开始之前function1 确实完成function2。由于线程如何调度和执行的不可预测性,使用Thread.Sleep该作业并不总是有效。

另一个问题Thread.Sleep是它阻塞了 UI 线程。在基于 UI 的应用程序中使用多线程时的第一条规则是永远不要阻塞 UI 线程。这适用于任何类型的阻塞调用,包括Thread.Sleep, ManualResetEvent,Thread.Join等。

我解决这个问题的方法是将Task类与ContinueWith方法一起使用。这将在调用之前等待function1完成,function2而不会阻塞 UI 线程。

private void Form1_Load(object sender, EventArgs e)
{
  TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

  Task.Factory.StartNew(() =>
  {
    function1();
  }).ContinueWith((task =>
  {
    function2();
  }, ui);
}
于 2012-04-19T13:50:40.410 回答
0

由于缺少“;”,您提供的代码将无法编译 在 Sleep(500) 调用之后。

当语法固定时,它在我的盒子上“工作”。

您没有安全的方式来表明它已经完成。您正在学习,第一课 - 不要等待带有 sleep() 调用的线程。

BackgroundWorker 组件会更容易使用 - 您不必担心显式信号会返回结果。

如果您想坚持使用 Thread 实例,请查看 autoResetEvent 类或 Thread.Join()。

在此处输入图像描述

于 2012-04-19T10:27:37.670 回答