Aracılığıyla paylaş


Denetimlere iş parçacığı güvenli çağrılar yapma (Windows Forms .NET)

Çoklu iş parçacığı kullanımı, Windows Forms uygulamalarının performansını artırabilir, ancak Windows Forms denetimlerine erişim doğal olarak iş parçacığı açısından güvenli değildir. Çoklu iş parçacığı kullanımı kodunuzu ciddi ve karmaşık hatalara maruz bırakabilir. Denetimi yönlendiren iki veya daha fazla iş parçacığı, denetimi tutarsız bir duruma zorlayabilir ve yarış koşullarına, kilitlenmelere ve donmalara veya kilitlenmelere yol açabilir. Uygulamanızda çok iş parçacığı kullanımı uygularsanız, iş parçacığı arası denetimleri iş parçacığı güvenli bir şekilde çağırdığınızdan emin olun. Daha fazla bilgi için bkz . Yönetilen iş parçacığı oluşturma en iyi yöntemleri.

Önemli

.NET 7 ve .NET 6 için Masaüstü Kılavuzu belgeleri yapım aşamasındadır.

Bu denetimi oluşturmayan bir iş parçacığından Windows Forms denetimini güvenli bir şekilde çağırmanın iki yolu vardır. System.Windows.Forms.Control.Invoke Ana iş parçacığında oluşturulan ve ardından denetimi çağıran bir temsilciyi çağırmak için yöntemini kullanın. Alternatif olarak, arka plan iş parçacığında yapılan işleri sonuçlar üzerinde raporlamadan ayırmak için olay temelli bir model kullanan bir System.ComponentModel.BackgroundWorkeruygulayabilirsiniz.

Güvenli olmayan iş parçacıkları arası çağrılar

Doğrudan oluşturmamış bir iş parçacığından bir denetimi çağırmak güvenli değildir. Aşağıdaki kod parçacığı, denetime yönelik güvenli olmayan bir çağrıyı System.Windows.Forms.TextBox gösterir. Olay işleyicisi Button1_Click , ana iş parçacığının özelliğini doğrudan ayarlayan yeni WriteTextUnsafe bir iş parçacığı TextBox.Text oluşturur.

private void button1_Click(object sender, EventArgs e)
{
    var thread2 = new System.Threading.Thread(WriteTextUnsafe);
    thread2.Start();
}

private void WriteTextUnsafe() =>
    textBox1.Text = "This text was set unsafely.";
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim thread2 As New System.Threading.Thread(AddressOf WriteTextUnsafe)
    thread2.Start()
End Sub

Private Sub WriteTextUnsafe()
    TextBox1.Text = "This text was set unsafely."
End Sub

Visual Studio hata ayıklayıcısı, iş parçacıkları arası işlem geçerli değil iletisiyle bir InvalidOperationException oluşturarak bu güvenli olmayan iş parçacığı çağrılarını algılar. Denetim, oluşturulduğu iş parçacığı dışında bir iş parçacığından erişilir. Her InvalidOperationException zaman Visual Studio hata ayıklaması sırasında güvenli olmayan iş parçacıkları arası çağrılar için gerçekleşir ve uygulama çalışma zamanında gerçekleşebilir. Sorunu düzeltmeniz gerekir, ancak özelliğini falseolarak ayarlayarak Control.CheckForIllegalCrossThreadCalls özel durumu devre dışı bırakabilirsiniz.

İş parçacıkları arası çağrıları Kasa

Aşağıdaki kod örnekleri, oluşturmamış bir iş parçacığından Windows Forms denetimini güvenli bir şekilde çağırmanın iki yolunu gösterir:

  1. Denetimi System.Windows.Forms.Control.Invoke çağırmak için ana iş parçacığından bir temsilci çağıran yöntemi.
  2. System.ComponentModel.BackgroundWorker Olay temelli model sunan bir bileşen.

Her iki örnekte de arka plan iş parçacığı, bu iş parçacığında yapılan işlerin benzetimini yapmak için bir saniye boyunca uykudadır.

Örnek: Invoke yöntemini kullanma

Aşağıdaki örnek, Windows Forms denetimine iş parçacığı açısından güvenli çağrılar sağlamaya yönelik bir deseni gösterir. Denetimin System.Windows.Forms.Control.InvokeRequired oluşturma iş parçacığı kimliğini çağıran iş parçacığı kimliğiyle karşılaştıran özelliğini sorgular. Farklıysa yöntemini çağırmanız Control.Invoke gerekir.

denetimin WriteTextSafeTextBoxText özelliğini yeni bir değere ayarlamayı etkinleştirir. yöntemi sorgular InvokeRequired. döndürürsetrueInvokeRequired, WriteTextSafe yöntemini yöntemine temsilci Invoke olarak geçirerek özyinelemeli olarak kendisini çağırır. döndürürse InvokeRequiredfalse, WriteTextSafe öğesini doğrudan ayarlar TextBox.Text . Olay işleyicisi Button1_Click yeni iş parçacığını oluşturur ve yöntemini çalıştırır WriteTextSafe .

private void button1_Click(object sender, EventArgs e)
{
    var threadParameters = new System.Threading.ThreadStart(delegate { WriteTextSafe("This text was set safely."); });
    var thread2 = new System.Threading.Thread(threadParameters);
    thread2.Start();
}

public void WriteTextSafe(string text)
{
    if (textBox1.InvokeRequired)
    {
        // Call this same method but append THREAD2 to the text
        Action safeWrite = delegate { WriteTextSafe($"{text} (THREAD2)"); };
        textBox1.Invoke(safeWrite);
    }
    else
        textBox1.Text = text;
}
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Dim threadParameters As New System.Threading.ThreadStart(Sub()
                                                                 WriteTextSafe("This text was set safely.")
                                                             End Sub)

    Dim thread2 As New System.Threading.Thread(threadParameters)
    thread2.Start()

End Sub

Private Sub WriteTextSafe(text As String)

    If (TextBox1.InvokeRequired) Then

        TextBox1.Invoke(Sub()
                            WriteTextSafe($"{text} (THREAD2)")
                        End Sub)

    Else
        TextBox1.Text = text
    End If

End Sub

Örnek: BackgroundWorker kullanma

Çok iş parçacıklı işlem gerçekleştirmenin System.ComponentModel.BackgroundWorker kolay bir yolu, olay temelli bir model kullanan bileşendir. Arka plan iş parçacığı olayı oluşturur BackgroundWorker.DoWork ve ana iş parçacığıyla etkileşim kurmaz. Ana iş parçacığı, ana iş parçacığının BackgroundWorker.ProgressChanged denetimlerini çağırabilen ve BackgroundWorker.RunWorkerCompleted olay işleyicilerini çalıştırır.

kullanarak BackgroundWorkeriş parçacığı güvenli bir çağrı yapmak için olayı işleyebilir DoWork . Arka plan çalışanının durumu bildirmek için kullandığı iki olay vardır: ProgressChanged ve RunWorkerCompleted. Olay ProgressChanged , durum güncelleştirmelerini ana iş parçacığına iletmek için kullanılır ve RunWorkerCompleted olay arka plan çalışanının işini tamamlandığını bildirmek için kullanılır. Arka plan iş parçacığını başlatmak için öğesini çağırın BackgroundWorker.RunWorkerAsync.

Örnek olayda 0'dan 10'a DoWork kadar sayar ve sayımlar arasında bir saniye boyunca duraklar. Olay işleyicisini ProgressChanged kullanarak sayıyı ana iş parçacığına geri bildirir ve denetimin TextBoxText özelliğini ayarlar. ProgressChanged Olayın çalışması BackgroundWorker.WorkerReportsProgress için özelliği olarak trueayarlanmalıdır.

private void button1_Click(object sender, EventArgs e)
{
    if (!backgroundWorker1.IsBusy)
        backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    int counter = 0;
    int max = 10;

    while (counter <= max)
    {
        backgroundWorker1.ReportProgress(0, counter.ToString());
        System.Threading.Thread.Sleep(1000);
        counter++;
    }
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) =>
    textBox1.Text = (string)e.UserState;
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    If (Not BackgroundWorker1.IsBusy) Then
        BackgroundWorker1.RunWorkerAsync()
    End If

End Sub

Private Sub BackgroundWorker1_DoWork(sender As Object, e As ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

    Dim counter = 0
    Dim max = 10

    While counter <= max

        BackgroundWorker1.ReportProgress(0, counter.ToString())
        System.Threading.Thread.Sleep(1000)

        counter += 1

    End While

End Sub

Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    TextBox1.Text = e.UserState
End Sub