应用程序停止在新线程函数中工作

application stop working in new thread function

当我使用消息框来跟踪程序停止的位置时 在 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);
    }
}





          

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


更长的版本:

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

1.

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

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


2.

Thread.Sleep(2000);

您正在阻塞 UI 线程,因此任何用户交互时间超过 2 秒,这是 CS101 及以后的大忌,请考虑在此处使用任务和 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方法[=19] =]

另一种选择是使用 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
    }