【问题标题】:application stop working in new thread function应用程序停止在新线程函数中工作
【发布时间】:2017-01-31 04:39:07
【问题描述】:

当我使用消息框来跟踪程序停止的位置时 在com.CommandText 它什么也没显示,应用程序挂起(冻结)。

如果我在没有Thread 的情况下使用它,同样的功能可以完美运行。

这是什么原因?

public bool load_complete=false;  

private void button7_Click(object sender, EventArgs e)
{
    Thread t1 = new Thread(new ThreadStart(load_data));  
    t1.Start();
    Thread.Sleep(2000);
    while (load_complete == false) ;
    t1.Abort();
}


public void load_data()
{
    string connectionString = @"Data Source=(LocalDB)\v11.0;AttachDbFilename=" + Application.StartupPath + "\\Database1.mdf;Integrated Security=True;";

    SqlConnection conn = new SqlConnection(connectionString);
    conn.Open();
    MessageBox.Show("open");
    SqlCommand com = new SqlCommand();
    try
    {
        com.Connection = conn; 
        DataSet ds = new DataSet(); 
        DataTable dt = new DataTable(); 
       
        SqlDataAdapter da = new SqlDataAdapter(); 
        com.CommandText = "select username,password from login where username ='" + textBox1.Text + "'"; 
        da.SelectCommand = com;
        da.Fill(dt);
        dataGridView1.DataSource = dt; 

        username = (string)this.dataGridView1.Rows[0].Cells[0].Value;
        pass = (string)this.dataGridView1.Rows[0].Cells[1].Value;
        load_complete = true;
        
    }
    catch (Exception  ex){
        MessageBox.Show(ex.Message);
    }
}





          

【问题讨论】:

  • 你能用异步任务代替线程吗?

标签: .net multithreading c#-4.0


【解决方案1】:

短版:您正在阻塞处理消息框显示的 UI 线程,不要阻塞 UI 线程


加长版:

上面列出的代码存在许多问题。 让我们从显而易见的开始:

1.

public bool load_complete=false;
...
while (load_complete == false) ;

您的 flag 没有标记为 volatile 并且编译器优化可能假定由单个线程访问,在这种情况下,您的代码将永远停留在 UI 中。如果不是因为代码中的许多其他问题,我建议在这里使用 volatile...


2.

Thread.Sleep(2000);

您正在阻塞 UI 线程,因此任何用户交互都会阻塞 2 秒以上,这是 CS101 及以后的一个大禁忌,请考虑在此处使用 Tasks 和 async/await 以保持 UI 不间断。对仍使用 SqlDataAdapter 的代码的最小更改需要:

a) 将按钮处理程序标记为异步并等待您需要的任何内容:

private async void button7_Click(object sender, EventArgs e)
{
    await load_data();  
    // more UI code is free to go here
}

b) 在线程池上异步运行 load_data 并将 Task 对象返回给调用者:

public Task load_data()
{
     return Task.Run( () => 
     {
         // paste your old load_data code here verbatim
     });
}

3.

t1.Abort();

无法想象那个线程对你做了什么,所以你想冷血地打断它。线程到达你传入的函数的末尾就会终止,这里绝对不需要手动中止,如果下次遇到需要等待线程的情况,请考虑Join方法

【讨论】:

  • 我发现错误出现在文本框控件上,因为新线程无法更改或获取主线程中的值,所以我将文本框的值存储到可验证的字符串中,因此我更改了查询 cammandtext by com.CommandText = "select username,password from login where username ='" + textBox1.Text + "'"; by com.CommandText = "select username,password from login where username ='" + userName + "'";
  • 你是对的@oleg 我是由主线程运行的,它阻塞了主 UI 线程现在我在一个新线程中运行它现在它完美了
【解决方案2】:

另一种选择是使用 BackgroundWorker,正如它所说,它使用不会占用您的主 UI 线程的后台线程。它已经附带了流程完成时的事件。

您只需将一个 BackgroundWorker 从工具箱拖到您的表单中。

注意:在您的 LoadData 方法中,您无法访问任何表单元素,因此您必须取出 MessageBox。您可以在 BackgroundWorker 完成的事件处理程序中引用表单元素。

    private void button7_Click(object sender, EventArgs e)
    {
          MyWorker.RunWorkerAsync();
    }

    private void MyWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        LoadData();
    }
    private void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            string username = (string)this.dataGridView1.Rows[0].Cells[0].Value;
            string pass = (string)this.dataGridView1.Rows[0].Cells[1].Value;
        }
        else
        {
            MessageBox.Show("Houston we have a problem");
        }

    }
    private void LoadData()
    {
        // Load your datagridview
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多