【问题标题】:Increase a variable in a loop and for each increment, apply for each new thread在循环中增加一个变量,对于每个增量,应用到每个新线程
【发布时间】:2021-08-27 09:18:28
【问题描述】:

每次我创建一个新的Thread 并存储该值时,如何增加一个变量?我想在每个线程中为不同的数据库做 mysqlbackup,我会在 Class1.cs 上完成 curBytes/totalBytes。我想将该值更新为datagridview.Row[iterate].Cell[2] 在线程之间同时进行,其中迭代对应于第一个线程的值 0,第二个线程的值 1,依此类推。

我尝试过使用Interlocked.Incrementlock(),但它们似乎不起作用。我不想使用BackgroundWorker

这是我没有做任何更改的代码datagridIterate(遍历datagridview Rows的值)

Form.cs:

private void button1_Click(object sender, EventArgs e)
{
    restoreUI();
}

public void restoreUI()
{
    mysqlUtils msu = new mysqlUtils(); 
    foreach(DataGridViewRow row in dataGridView1.Rows)
    {
        Thread t = new Thread(() =>
        {
            msu.Restore(row.Cells[1].Value?.ToString(), server.Text, username.Text,
                pwd.Text, row.Cells[0].Value?.ToString());
        }
        t.Start();
    }
}

Class1.cs:


namespace Utils
{
    public class mysqlUtils
    {
        public int total;
        public int cur;

        public void Restore(string filename, string server, string user,
            string password, string db)
        {
            string constring = "server=" + server + ";user=" + user +
                ";pwd=" + password + ";database=" + db + ";";
            string file = "C:\\Users\\SQL FILES\\" + filename;
            using (MySqlConnection conn = new MySqlConnection(constring))
            {
                using (MySqlCommand cmd = new MySqlCommand())
                {
                    using (MySqlBackup mb = new MySqlBackup(cmd))
                    {
                        cmd.Connection = conn;
                        conn.Open();

                        mb.ImportInfo.IntervalForProgressReport = 50;

                        mb.ImportProgressChanged += updateProgress;
                        mb.ImportFromFile(file);

                        conn.Close();
                    }
                }
            }
        }
    }

    public void updateProgress(object sender, ImportProgressArgs e)
    {
        total = (int)e.TotalBytes;
        cur = (int)e.CurrentBytes;
        Form4 form4 = (Form4)Application.OpenForms[0];
        form4.updateProgressValue(total, cur);
    }
}

我应该如何设法更改datagridIterate,它的值i 用于第一个线程,i+1 用于下一个线程等等?如果您有任何支持,我将不胜感激。

【问题讨论】:

  • 请考虑发布minimal reproducible example
  • 我将假设对msu.Restore 的调用非常耗时。但似乎它可能正在对数据网格做一些事情 - 但是线程中不允许这样做。我们真的需要看到完整的代码。
  • 我现在编辑一下,需要几分钟时间
  • 您无法在非 UI 线程中访问任何 UI 元素。所有参数row.Cells[1].Value?.ToString(), server.Text, username.Text, pwd.Text, row.Cells[0].Value?.ToString()在线程内部都无法访问。
  • mysqlUtils 类中调用 Form4 form4 = (Form4)Application.OpenForms[0]; 是一个糟糕的设计,因为它会创建从 DB 到 UI 的强耦合。这通常非常糟糕。

标签: c# multithreading winforms mysql-backup


【解决方案1】:

这里有一个重要的代码提示,可以帮助你理解你需要什么。

试试这个:

public class Form4 : Form
{
    private DataGridView dataGridView1 = new DataGridView();
    private TextBox server = new TextBox();
    private TextBox username = new TextBox();
    private TextBox pwd = new TextBox();

    private void button1_Click(object sender, EventArgs e)
    {
        RestoreUI();
    }

    public void RestoreUI()
    {
        MySqlUtils msu = new MySqlUtils();
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            string filename = row.Cells[1].Value?.ToString();
            string s = server.Text;
            string user = username.Text;
            string password = pwd.Text;
            string db = row.Cells[0].Value?.ToString();
            Thread t = new Thread(() => msu.Restore(filename, s, user, password, db, UpdateProgress));
            t.Start();
        }
    }

    public void UpdateProgress(object sender, ImportProgressArgs e)
    {
        this.Invoke((Action)(() =>
        {
            /* add your code here to update the UI */
        }));
    }
}

还有你的MySqlUtils 班级。

public class MySqlUtils
{
    public void Restore(string filename, string server, string user, string password, string db, ImportProgressChange updateProgress)
    {
        string constring = "server=" + server + ";user=" + user + ";pwd=" + password + ";database=" + db + ";";
        string file = "C:\\Users\\SQL FILES\\" + filename;
        using (MySqlConnection conn = new MySqlConnection(constring))
        {
            using (MySqlCommand cmd = new MySqlCommand())
            {
                using (MySqlBackup mb = new MySqlBackup(cmd))
                {
                    cmd.Connection = conn;
                    conn.Open();

                    mb.ImportInfo.IntervalForProgressReport = 50;

                    mb.ImportProgressChanged += updateProgress;
                    mb.ImportFromFile(file);

                    conn.Close();
                }
            }
        }
    }
}

注意:我已将命名约定更改为标准 C#。

【讨论】:

  • 您好,先生,本来应该早点回复您的,但我打算等我的问题有最终答案后再回复您,现在还没有找到答案
  • 有什么方法可以在 UpdateProgress 中添加更多变量。例如:public void UpdateProgress(object sender, ImportProgressArgs e, *int datagridIterate*) 以及如何在我的 Restore() 函数中处理它
  • datagridIterate 变量的目的是在foreach (DataGridViewRow row in dataGridView1.Rows) 中保存我的Datagridview 迭代,
  • public void UpdateProgressValue(object sender, ImportProgressArgs e,int datagridIterate) { this.Invoke((Action)(() => { double percent = ((double)e.CurrentBytes / (double)e.TotalBytes) * 100; string sPercent = percent.ToString("n2"); curPercent = sPercent + "%"; if (datagridIterate == dataGridView1.Rows.Count - 1) return; this.dataGridView1.Rows[datagridIterate].Cells[2].Value = curPercent; })); }
  • 最初,我没有将 int datagridIterate 添加到 UpdateProgressValue 中,而是在 Class1 中创建了一个公共 int ,并且每次线程激活 Restore(///,int iterate){ datagridIterate=iterate;} 时都会更新它,但该公共 int 将在跨线程时更新一个新的线程会激活代码,因此不会有一个线程的特定值,而是会跨线程更改,我的 datagridview 会更新最后一行的值
猜你喜欢
  • 1970-01-01
  • 2020-12-29
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多