在主线程中创建对象并在另一个线程中使用它们。怎么做?

时间:2012-04-19 10:21:42

标签: c# multithreading object

现在,它输出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 个答案:

答案 0 :(得分:2)

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

这意味着您的两个操作依次依赖,无法并行执行。在这里使用线程毫无意义。

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

答案 1 :(得分:2)

实际上您的程序正在按预期在我的计算机上运行。那么为什么它不能在您的计算机上工作(或者仅在有时工作)?这是因为您的计划中存在竞争条件。这意味着您的程序假定第二个线程(执行function1)将在不到500ms的时间内为数组分配新值。永远不要假设其他线程完成它的任务需要多长时间。操作系统可以自由选择单个线程执行的时间,频率和时间以及暂停时间。相反,使用同步原语(例如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();
    }

答案 2 :(得分:1)

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

Thread.Sleep的另一个问题是它阻止了UI线程。在基于UI的应用程序中使用多线程时的首要规则是永远不会阻止UI线程。这适用于任何类型的屏蔽通话,包括Thread.SleepManualResetEventThread.Join等。

我解决此问题的方法是使用Task类和ContinueWith方法。这将等待function1完成,然后在不阻止UI线程的情况下调用function2

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

  Task.Factory.StartNew(() =>
  {
    function1();
  }).ContinueWith((task =>
  {
    function2();
  }, ui);
}

答案 3 :(得分:0)

由于缺少';',您提供的代码将无法编译睡觉(500)电话。

当语法修复时,它在我的盒子上“起作用”。

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

BackgroundWorker组件更易于使用 - 您不必担心显式信令以获得结果。

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

enter image description here