如何运行多线程应用程序?

时间:2009-05-28 11:12:29

标签: c# .net winforms

这些代码会产生这个错误:

跨线程操作无效:控制'progressBar2'从其创建的线程以外的线程访问。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadingTest1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        ThreadStart ts1;
        ThreadStart ts2;
        Thread t1;
        Thread t2;

        private void btnStart_Click(object sender, EventArgs e)
        {
            ts1 = new ThreadStart(z1);
            ts2 = new ThreadStart(z2);

            t1 = new Thread(ts1);
            t2 = new Thread(ts2);

            t1.Start(); 
            t2.Start();

            btnStart.Enabled = false;
        }

        public void z1()
        {

            for (int i = 1; i < 60; ++i)
            {
                progressBar1.Value += 1;
                for (int j = 1; j < 10000000; ++j)
                {
                    j += 1;
                }
            }
        }

        public void z2()
        {
            for (int k = 1; k < 100; ++k)
            {
                progressBar2.Value += 1;
                for (int j = 1; j < 25000000; ++j)
                {
                    j += 1;
                }
            }
        }

        private void btnstop_Click(object sender, EventArgs e)
        {
            t1.Suspend(); 
            t2.Suspend();
        }

        private void btnContinue_Click(object sender, EventArgs e)
        {
            t1.Resume(); 
            t2.Resume();

        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            if (t1.IsAlive)
            {
                MessageBox.Show("Çalışan threadler var program sonlanamaz.");
            }
            else
            {
                this.Close();
            } 

        }
    }
}

3 个答案:

答案 0 :(得分:7)

您无法访问负责该控件的UI线程以外的线程中的UI控件。

请参阅我的线程教程中的WinForms页面,并在BackgroundWorker上搜索教程,这是.NET 2.0中引入的一个组件,它使生活更加轻松(特别是对于进度条)。

此外,我会尽量避免使用Thread.Suspend / Resume,而是采用更合作的方式(例如Monitor.Wait / Pulse)。这样可以避免在持有锁等时挂起线程

答案 1 :(得分:1)

对于z1和z2这样做: 添加zSafe() 在InvokeRequired检查之后,在z()内调用zSafe()。

public void z1Safe()
        {

            for (int i = 1; i < 60; ++i)
            {
                progressBar1.Value += 1;
                for (int j = 1; j < 10000000; ++j)
                {
                    j += 1;
                }
            }
        }

        public void z1()
        {

            if (this.InvokeRequired)
            {
                this.Invoke((MethodInvoker)delegate { z1Safe(); });
            }
            else
                z1Safe();
        }

我刚刚在我的Windows窗体中为asyn del call实现了一个类似的解决方案,它运行正常。

答案 2 :(得分:0)

当您处理多线程应用程序时,交叉线程异常非常常见,当您尝试在除其自己的线程之外的线程中调用控件的成员时,它会发生。为了避免这种情况,您可以检查该控件的InvokeRequired属性并在其自己的线程中调用委托或使用BackgroundWorker在后台运行进程(另一个线程)并处理其事件,当您处理BackgroundWorker事件时,事件处理程序方法将在主线程上运行,因此不需要调用委托

Here您可以找到有关BackgroundWorker的一些信息