简体   繁体   English

C# 中的线程异常错误:跨线程操作无效:从跨线程操作访问的控制“lblp4”无效

[英]Thread exception error in C# :Cross-thread operation not valid: Control 'lblp4' accessed from a Cross-thread operation not valid

First, sorry for my weak english language, I'm beginner programmer.首先,抱歉我的英语能力很差,我是初学者程序员。 In my project I use thread class, but when finished it I see this exception :在我的项目中,我使用线程类,但完成后我看到这个异常:

Cross-thread operation not valid: Control 'lblp4' accessed from a thread other than the thread it was created on.跨线程操作无效:控制“lblp4”从创建它的线程以外的线程访问。

In my project, I call 5 functions Synchronize from Philosopher class in Form1 class:在我的项目中,我从Form1类中的Philosopher类调用 5 个函数Synchronize

Philosopher class: Philosopher课:

namespace AZsys 
{
class Philosopher 
{
    public Int32 i;

    public bool e, th;
    public Philosopher()
    {

    }
    public void main()
    {
        lock (AZsys.Program.frm.locker)
        {
            while (true)
            {
                if (i < 0 || i > 4)
                {
                    System.Windows.Forms.MessageBox.Show("error");
                    break;
                }
                else
                {
                    think();
                    AZsys.Program.frm.chopstick[i].WaitOne();
                    AZsys.Program.frm.chopstick[(i + 1) % 5].WaitOne();
                    eat();
                    AZsys.Program.frm.chopstick[(i + 1) % 5].Release();
                    AZsys.Program.frm.chopstick[i].Release();
                }
            }
        }
        Thread.Sleep(100);
    }
    private void eat()
    {
            switch (i)
            {
                case 1:
                    AZsys.Program.frm.lblp1.Text = "Eating...";
                    break;
                case 2:
                    AZsys.Program.frm.lblp2.Text = "Eating...";
                    break;
                case 3:
                    AZsys.Program.frm.lblp3.Text = "Eating...";
                    break;
                case 4:
                    AZsys.Program.frm.lblp4.Text = "Eating...";
                    break;
                case 5:
                    AZsys.Program.frm.lblp5.Text = "Eating...";
                    break;
            }
        e = true;

        for (int j = 0; j < 992; j++)
        {
            if (j % 8 == 0)
                e = true;
        }
        e = false;
    }

    private void think()
    {
            switch (i)
            {
                case 1:
                    AZsys.Program.frm.lblp1.Text = "Thinking..."+Thread.CurrentThread.Name.ToString();
                    break;
                case 2:
                    AZsys.Program.frm.lblp2.Text = "Thinking..."+Thread.CurrentThread.Name.ToString();
                    break;
                case 3:
                    AZsys.Program.frm.lblp3.Text = "Thinking..."+Thread.CurrentThread.Name.ToString();
                    break;
                case 4:
                    AZsys.Program.frm.lblp4.Text = "Thinking..."+Thread.CurrentThread.Name.ToString();
                    break;
                case 5:
                    AZsys.Program.frm.lblp5.Text = "Thinking..." + Thread.CurrentThread.Name.ToString();
                    break;
            }

        th = true;

        for (int j = 0; j < 9924; j++)
        {
            if (j % 8 == 0)
                th = true;
        }
        th = false;
    }
}

Even in this code, I use lock ( locker ) but don't work!!!即使在这段代码中,我也使用了 lock ( locker ) 但不起作用!!!

Form1 class: Form1类:

   public partial class Form1 : Form
{
    public  Semaphore[] chopstick;
    public  object locker;

    private Philosopher ph1;
    private Philosopher ph2;
    private Philosopher ph3;
    private Philosopher ph4;
    private Philosopher ph5;

    public Form1()
    {
        InitializeComponent();
        chopstick = new Semaphore[5];



    }

    private void Form1_Load(object sender, EventArgs e)
    {
        locker = new object();
        ph1 = new Philosopher();
        ph1.i = 1;
        ph2 = new Philosopher();
        ph2.i = 2;
        ph3 = new Philosopher();
        ph3.i = 3;
        ph4 = new Philosopher();
        ph4.i = 4;
        ph5 = new Philosopher();
        ph5.i = 5;
    }

    private void lblp2_Click(object sender, EventArgs e)
    {

    }

    private void btnstart_Click(object sender, EventArgs e)
    {
        Thread.CurrentThread.Priority = ThreadPriority.Lowest;



        Thread t1 = new  Thread(ph1.main);
        Thread t2 = new  Thread(ph2.main);
        Thread t3 = new Thread(ph3.main);
        Thread t4 = new Thread(ph4.main);
        Thread t5 = new Thread(ph5.main);


        t1.Name = "t1";

        t2.Name = "t2";

        t3.Name = "t3";

        t4.Name = "t4";

        t5.Name = "t5";


      t1.Priority = ThreadPriority.Highest;
      t2.Priority = ThreadPriority.Highest;
      t3.Priority = ThreadPriority.Highest;
      t4.Priority = ThreadPriority.Highest;
      t5.Priority = ThreadPriority.Highest;
     // Thread.Sleep(100);
        t4.Start();
        Thread.Sleep(100);
        t1.Start();
        Thread.Sleep(100);
        t2.Start();
        Thread.Sleep(100);
        t3.Start();
        Thread.Sleep(100);
        t5.Start();
        Thread.Sleep(100);
    }
}

} }

As the exception suggests, you're accessing controls from a thread other than the one that that created the control (specifically, your ph1..5 threads all attempt to access the UI).正如例外情况所暗示的那样,您正在从创建控件的线程以外的线程访问控件(具体来说,您的 ph1..5 线程都尝试访问 UI)。

To correct this, you need to use the Invoke() method on the controls so that the accesses are performed on the main UI thread.要纠正此问题,您需要在控件上使用Invoke()方法,以便在主 UI 线程上执行访问。

Perhaps add a function to Philosopher as follows:也许向Philosopher添加一个函数,如下所示:

private void UpdateText(Label label, string text)
{
    // If the current thread is not the UI thread, InvokeRequired will be true
    if (label.InvokeRequired)
    {
        // If so, call Invoke, passing it a lambda expression which calls
        // UpdateText with the same label and text, but on the UI thread instead.
        label.Invoke((Action)(() => UpdateText(label, text)));
        return;
    }
    // If we're running on the UI thread, we'll get here, and can safely update 
    // the label's text.
    label.Text = text;
}

Then, whenever you have something like:然后,每当你有类似的东西时:

AZsys.Program.frm.lblp1.Text = "Eating...";

Replace it with:替换为:

UpdateText(AZsys.Program.frm.lblp1, "Eating...");

In my case the intention was to change the behavior of a component "Janus.Windows.Ribbon.CommandBase" (applies to any other type) to enable or disable from another form.就我而言,目的是更改组件“Janus.Windows.Ribbon.CommandBase”(适用于任何其他类型)的行为,以从其他表单启用或禁用。 And the behavior change was done from an onchange method that listened for the changes of the components.行为更改是通过监听组件更改的 onchange 方法完成的。

This implementation was carried out with the steps suggested by the Microsoft documentation ( https://docs.microsoft.com/es-es/dotnet/desktop/winforms/controls/how-to-make-thread-safe-calls-to- windows-forms-controls? view = netframeworkdesktop-4.8)此实现是按照 Microsoft 文档 ( https://docs.microsoft.com/es-es/dotnet/desktop/winforms/controls/how-to-make-thread-safe-calls-to-)建议的步骤执行的windows-forms-controls?view = netframeworkdesktop-4.8)

First the safe call was declared with the parameter that must be of the data type of the property to change.首先,使用必须是要更改的属性的数据类型的参数来声明安全调用。

private delegate void SaveCallDelegate(bool enable);

Variable to capture the properties of the component being modified用于捕获被修改组件的属性的变量

private CommandBase cm;

OnChange event queries if the component should be called safely and if so, it calls the "SaveCallChange" method with the value to change. OnChange 事件查询是否应该安全地调用组件,如果是,它会调用“SaveCallChange”方法,并使用要更改的值。

protected override void OnChanged(Command command){
   base.OnCommandChanged(command);
   
   foreach (KeyValuePair<CommandBase, List<string>> p in Invokers)
   {
      if (p.Key.Ribbon != null && p.Key.Ribbon.InvokeRequired)
      {
         cm = p.Key;
         SaveCallChange((command.Status == CommandStatus.Enabled));
      }
      else {
         p.Key.Enabled = (command.Status == CommandStatus.Enabled);
      }
   }
}

Invokers comes from the EventCommandAdapter class ("Microsoft.Practices.CompositeUI.Commands") which inherits the main class. Invokers 来自 EventCommandAdapter 类(“Microsoft.Practices.CompositeUI.Commands”),它继承了主类。

Finally there are the two methods that carry out the safe process of change最后有两种方法可以执行安全的变更过程

private void SaveCallChange(bool enable){
    var e = new SaveCallDelegate(setEnable);
    cm.Ribbon.Invoke(e, new object[] { enable });
}

private void setEnable(bool enable) {
    this.cm.Enabled = enable;
}

我可以看到的主要问题是从线程访问用户界面

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 跨线程操作无效C# - Cross-thread operation not valid c# 跨线程操作在C#中无效? - Cross-thread operation not valid in C#? 跨线程操作无效 - Cross-thread operation not valid 跨线程操作无效 - Cross-thread operation not valid 跨线程操作在父控件中无效 - Cross-thread operation not valid in parent control 无效的操作异常-“跨线程操作无效:控件&#39;TextBox1&#39;从创建该线程的线程之外的线程访问。” - Invalid Operation Exception - “Cross-thread operation not valid: Control 'TextBox1' accessed from a thread other than the thread it was created on.” 不一致的“跨线程操作无效”异常 - Inconsistent “Cross-thread operation not valid” exception ParallelFor | 跨线程操作无效:从创建该线程的线程以外的线程访问控件 - ParallelFor | Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on 跨线程操作无效:控制&#39;&#39;从窗口形式创建的线程以外的线程访问 - Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on in window form 跨线程操作无效:从不是在其上创建线程的线程访问控件“ lbDatabase” - Cross-thread operation not valid: Control 'lbDatabase' accessed from a thread other than the thread it was created on
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM