【问题标题】:Cross-thread operation not valid on using Parallel.Invoke [duplicate]使用 Parallel.Invoke 时跨线程操作无效 [重复]
【发布时间】:2016-10-06 06:01:23
【问题描述】:

我已经阅读了很多关于线程的解释,但我仍然很难理解。我在我的代码中尝试过,但收到如下错误:“附加信息:跨线程操作无效:控制 'dgvLocDatabase' 从创建它的线程以外的线程访问”。下面是我创建的代码。它必须将来自不同来源的数据添加到 2 个不同的 datagridview。

private void btnCountRecord_Click(object sender, EventArgs e)
{
    CountRecord();

    Parallel.Invoke(
        GetDevData,
        GetPcData
        );
}



private void GetDevData()
{

    if (bIsConnected == false)
    {
        MessageBox.Show(@"Please connect the device first", @"Error");
        return;
    }

    var sdwEnrollNumber = "";
    var idwTMachineNumber = 0;
    var idwEMachineNumber = 0;
    var idwVerifyMode = 0;
    var idwInOutMode = 0;
    var idwYear = 0;
    var idwMonth = 0;
    var idwDay = 0;
    var idwHour = 0;
    var idwMinute = 0;
    var idwSecond = 0;
    var idwWorkcode = 0;

    var idwErrorCode = 0;
    var iGlCount = 0;
    var iIndex = 0;

    dgvDevDatabase.Rows.Clear();


    axCZKEM1.EnableDevice(iMachineNumber, false); //disable the device
    if (axCZKEM1.ReadGeneralLogData(iMachineNumber)) //read all the attendance records to the memory
    {
        lblProgressBar.Text = @"Loading data. Please wait...";
        progBar.Visible = true;
        progBar.Maximum = _gRecCount;
        progBar.Minimum = 1;
        progBar.Value = 1;
        progBar.Step = 1;

        while (axCZKEM1.SSR_GetGeneralLogData(iMachineNumber, out sdwEnrollNumber, out idwVerifyMode,
                   out idwInOutMode, out idwYear, out idwMonth, out idwDay, out idwHour, out idwMinute, out idwSecond, ref idwWorkcode))//get records from the memory
        {
            iGlCount++;
            var bioId = sdwEnrollNumber;
            var timeLog = idwYear + "-" + idwMonth + "-" + idwDay + " " + idwHour + ":" 
                + idwMinute + ":" + idwSecond;
            dgvDevDatabase.Rows.Add(bioId, timeLog);
            progBar.PerformStep();
        }
        if (progBar.Value == _gRecCount) lblProgressBar.Text = @"";
    }
    else
    {
        Cursor = Cursors.Default;
        axCZKEM1.GetLastError(ref idwErrorCode);

        if (idwErrorCode != 0)
        {
            MessageBox.Show(@"Reading data from device failed. ErrorCode: " + idwErrorCode, @"Error");
        }
        else
        {
            MessageBox.Show(@"No data from terminal to return", @"Error");
        }
    }
    axCZKEM1.EnableDevice(iMachineNumber, true);//enable the device
}

private void GetPcData()
        {
            var tda = new TimeLogDataAccess();
            _rdr = tda.GetAllLogs();
            while (_rdr.HasRows && _rdr.Read())
            {
                dgvLocDatabase.Rows.Add(_rdr["bio_id"].ToString(), _rdr["time_log"].ToString());
            }
        }

如果我从 Parallel.Invoke 中删除“GetPcData”并将其替换为 Messagebox.Show(“Call me too”);,我不会收到错误,并且如果我只是自己运行“GetPcData” ,我也没有收到错误。所以我认为是 Parallel.Invoke 中的“GetPcData”导致了这个问题。

你能告诉我我做错了什么吗?如果你能向我解释更多这个parallel.invoke 或threading。谢谢。

【问题讨论】:

    标签: c# multithreading parallel-processing


    【解决方案1】:

    问题是,您尝试在线程之外的线程中修改 UI,UI 是从创建的线程。 查看 SynchronizationContext 类 (https://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext(v=vs.110).aspx) 并尝试以下操作: 在调用新线程之前分配 SynchronizationContext.Current 到一个变量。然后启动新线程,如果要更新 UI,请调用

    myContext.Post(cb => { doSomethingOnUi(); }, null);
    

    看看能不能解决你的问题。

    【讨论】:

    • 谢谢山姆怀斯。我不知道该怎么做。你能告诉我如何让我更有意义。
    • 查看我对 SynchronizationContext 的编辑
    猜你喜欢
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    相关资源
    最近更新 更多