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

时间:2017-01-31 04:39:07

标签: .net multithreading c#-4.0

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

// load_data()函数

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);
    }
}

2 个答案:

答案 0 :(得分:3)

简短版本:您正在阻止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方法

答案 1 :(得分:1)

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