在Invoke/BeginInvoke期间锁定会发生什么情况? (事件调度) [英] What happens to a lock during an Invoke/BeginInvoke? (event dispatching)

查看:201
本文介绍了在Invoke/BeginInvoke期间锁定会发生什么情况? (事件调度)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅需预先提出问题(请不要评论不良体系结构或如何进行修改-假设这是事实)

Just to put the questions upfront (please no comments about the bad architecture or how to revise - suppose this is what it is):

  1. 使用Invoke/BeginInvoke时,"lock"语句如何应用
  2. 以下代码会导致死锁吗?

假设我有以下BindingList,需要在GUI线程上进行更新:

Suppose I have the following BindingList that I need to update on the GUI Thread:

var AllItems = new BindingList<Item>();

我想确保对它的所有更新都已同步. 假设我有以下子例程进行一些计算,然后将新的条目插入到BindingList中:

I want to make sure that all updates to it are synchronized. Suppose I have the following subroutine to do some calculations and then insert a new entry into the BindingList:

private void MyFunc() {
  lock(locker) {
    ... //do some calculations with AllItems

    AddToArray(new Item(pos.ItemNo));

    ... //update some other structures with the contents of AllItems
    }
}

AddToArray看起来像:

And AddToArray looks like:

private void AddToArray (Item pitem)
{
   DoInGuiThread(() =>
     {
       lock (locker)
         {
           AllItems.Add(pitem);
         }
      });
 }

DoInGuiThread看起来像:

And DoInGuiThread looks like:

 private void DoInGuiThread(Action action) {
   if(InvokeRequired) {
       BeginInvoke(action);
    } else {
       action.Invoke();
    }
 }

推荐答案

该锁将一直保持到您离开lock块为止,您的当前代码不会导致死锁,但也无法正常工作.

The lock is held till you leave the lock block, your current code does not cause a deadlock however it also does not work correctly either.

这是事件的顺序:

  1. 在后台线程上,您调用MyFunc.
  2. 对象locker
  3. 的后台线程被锁定
  4. 后台线程将对AllItems进行一些计算"
  5. 后台线程从MyFunc调用AddToArray
  6. 调用AddToArray
  7. 后台线程从AddToArray
  8. 调用DoInGuiThread
  9. 后台线程从DoInGuiThread调用BeginInvoke,该线程不会阻塞,我将使用A表示后台线程 和B表示UI线程,这两种情况都发生在 同时.

  1. On a background thread you call MyFunc.
  2. A lock is taken for the background thread for the object locker
  3. The background thread will "do some calculations with AllItems"
  4. The background thread calls AddToArray from MyFunc passing in pitem
  5. The background thread calls DoInGuiThread from AddToArray
  6. The background thread calls BeginInvoke from DoInGuiThread, the thread does not block, I will use A to signify the background thread and B to signify the UI thread, both of these are happening at the same time.

A)BeginInvoke因为没有阻塞而从调用返回.
B)UI命中lock (locker)并阻塞,因为该锁由 后台线程.

A) BeginInvoke returns from it's call because it is non blocking.
B) The UI hits lock (locker) and blocks because the lock is held by the background thread.

您看到问题了吗? AddToArray返回,但是直到MyFunc的末尾才将对象添加到数组中,因此AddToArray之后的代码将在数组中没有该项目.

Do you see the issue? AddToArray returns but the object is not added to the array until the end of MyFunc so your code after AddToArray will not have the item in the array.

解决此问题的常规"方法是使用Invoke而不是BeginInvoke,但是这会导致死锁的发生.这是事件的顺序,最多6步是相同的,将被跳过.

The "usual" way to solve this is you use Invoke instead of BeginInvoke however that causes a deadlock to happen. This is the sequence of events, Steps up to 6 are the same and will be skipped.

  1. 后台线程从DoInGuiThread
  2. 调用Invoke
  3. A)Invoke等待B返回消息泵.
    B)用户界面命中lock (locker)并被阻止,因为该锁已被锁 后台线程.
  4. A)Invoke等待B返回消息泵.
    B)UI仍处于锁定状态,等待后台线程释放 锁.
  5. A)Invoke等待B返回消息泵.
    B)UI仍处于锁定状态,等待后台线程释放 锁.
  6. A)Invoke等待B返回消息泵.
    B)用户界面仍处于锁定状态,等待后台线程 释放锁.
  1. The background thread calls Invoke from DoInGuiThread
  2. A) Invoke waits for B to return to the message pump.
    B) The UI hits lock (locker) and blocks because the lock is held by the background thread.
  3. A) Invoke waits for B to return to the message pump.
    B) The UI is still locked up, waiting for the background thread to release the lock.
  4. A) Invoke waits for B to return to the message pump.
    B) The UI is still locked up, waiting for the background thread to release the lock.
  5. A) Invoke waits for B to return to the message pump.
    B) The UI is still locked up, waiting for the background thread to release the lock.

(这将永远重复)

这篇关于在Invoke/BeginInvoke期间锁定会发生什么情况? (事件调度)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆