向listBox添加线程安全方法

时间:2017-03-08 20:11:25

标签: c# thread-safety extension-methods

我有一个帖子,想要用进度更新列表,但表单控件不是线程安全的。所以我学会了解决article

问题是有更多的来源,每个来源都有自己的列表来显示进度。那么我如何使每个列表框都有自己的ThreadSafeSetText()方法来清理代码?

delegate void SetTextCallback(string text);
private async void btnRun_Click(object sender, EventArgs e)
{
   await Task.Run(() =>
   {
      importSource1();
   });

   //await Task.Run(() =>
   //{
   //   importSource2();
   //});
}

private void importSource1()
{
   // db stuff in a Parallel.For

   SetText("Result");
}

private void SetText(string text)
{
   // InvokeRequired required compares the thread ID of the
   // calling thread to the thread ID of the creating thread.
   // If these threads are different, it returns true.
   if (this.lstImportSource1.InvokeRequired)
   {
      SetTextCallback d = new SetTextCallback(SetText);
      this.Invoke(d, new object[] { text });
   }
   else
   {
      this.lstImportSource1.Items.Insert(0, text);
   }
}

1 个答案:

答案 0 :(得分:0)

根据ImportSource是执行数据库程序的方法的评论,我的建议使用async-await aproach。
当您的代码执行“触及”外部资源(数据库,文件系统,Web API等)的操作时,Async-await旨在实现更有效的资源使用。

因为在执行数据库查询(例如)期间,您的方法“什么都不做”,所以它只发送请求并等待响应。创建一个“无所事事”的新线程被视为浪费资源。

async-await操作将在一个线程上执行(大多数时间),您只需使用UI控件。

您可以为每个过程创建自己的异步方法

public async Task ExecuteProcedure1Async()
{
    using (var connection = new SqlConnection("connection string"))
    using (var command = new SqlCommand("dbo.sqlProcedure1", connection))
    {
        command.CommandType = CommandType.StoredProcedure;

        // Here execution will send request to the database
        // and be returned to the caller of this method         
        await connection.OpenAsync();
        // Continue after OpenAsync is completes and
        // Here execution will again will be returned to the caller 
        await command.ExecuteCommandAsync();
        // Continues after ExecuteCommandAsync is completed
    }      
}

可以为另一个存储过程创建类似的方法

以下所有程序将同时“几乎”执行 因为我们会在不等待回复的情况下发送请求 并且仅在所有程序完成时等待

private async Task ImportSource1Async()
{
    // Because asynchronoud method returns Task
    // We can create collection of tasks and "await" them all
    // after they have been started
    var tasks = new[] 
    {
        ExecuteProcedure1Async(),
        ExecuteProcedure2Async(),
        ExecuteProcedure3Async()
    };

    await Task.WhenAll(tasks);
}

然后,您可以在ImportSourceAsync eventhandler中将所有button_click方法组合在一起,并使用UI控件。

private async void btnRun_Click(object sender, EventArgs e)
{
    await ImportSource1Async();
    lstImportSource1.Items.Insert(0, "Import source 1 complete");

    await ImportSource2Async();
    lstImportSource1.Items.Insert(0, "Import source 2 complete");

    await ImportSource3Async();
    lstImportSource1.Items.Insert(0, "Import source 3 complete");
}