需要解释 win API“异步过程调用”相对于.NET

发布于 2024-11-04 13:39:37 字数 1263 浏览 1 评论 0原文

我有一个错误。在 WinForm .NET2.0 应用程序中,可以从鼠标单击事件处理程序调用我的 HeavyFunction。因此,当我开始快速单击时,由于第二次输入 HeavyFunction,我在文件写入时崩溃了。

我的解决方案。我想起了与APC相关的事情,并决定公平地同步这些事情。即我想排除 HeavyFunction 中的 APC 效应。所以,我使用了ThreadPool。对于同步,我尝试使用 SyncLock (Visual Basic)。但失败了。互斥体也不起作用。 我根本无法理解如何从同一个线程一次调用我的 HeavyFunction 两次。但确实如此。我认为如果我使用 ThreadPool 那么我会强制每个调用在不同的线程上执行。

APC 的定义 http://msdn.microsoft .com/en-us/library/ms681951%28v=vs.85%29.aspx
这是 Jeffrey Richter 的“CLR 中的线程同步公平性”(让我感到恶心): http://codeguru.earthweb.com/csharp/.net/net_general/threads/article.php/c4647/Thread-Synchronization-Fairness-in-the-CLR.htm

编辑:看来我找到了崩溃异常的原因。这是防病毒AVG。当有人点击速度非常快并导致快速文件打开/写入操作时,他可能会认为可疑活动。或者它会大大降低我的电脑速度。无论如何,当 AVG 禁用时我无法重现崩溃。尽管 ProcMon 显示 AVG 在启用时访问该文件。

最后,有人可以向我解释一下APC吗?即APC是否会导致同一线程中同一函数的双重输入? 我了解到它可以从这个 文本
“异步过程调用 (APC) 是在特定线程的上下文中异步执行的函数。当 APC 排队到线程时,系统会发出软件中断。下次调度线程时,它将运行APC功能”

如果没有这个了解我恐怕会死。

I have a bug. In WinForm .NET2.0 application my HeavyFunction can be called from mouse click event handlers. So, When I'm starting fast clicking I have crash on file writing because of HeavyFunction entered second time.

My solution. I remembered the things relative to APC and decided to synchronize the things fairly. I.e. I want to exclude APC effects in the HeavyFunction. So, I used ThreadPool. For synchronization I tried to use SyncLock (Visual Basic). And failed. Mutexes don't work either.
I simply cannot understand how my HeavyFunction can be called from the same thread twice at a time. But it does. I thought that if I use ThreadPool then I force every call be executed on different thread.

The definition of APC http://msdn.microsoft.com/en-us/library/ms681951%28v=vs.85%29.aspx.
Here is "Thread Synchronization Fairness in the CLR" by Jeffrey Richter (makes me sick):
http://codeguru.earthweb.com/csharp/.net/net_general/threads/article.php/c4647/Thread-Synchronization-Fairness-in-the-CLR.htm

EDIT: It seems that I found the reason of crash exception. It's antivirus AVG. Probably he considers suspicious activity when somebody clicks very fast and it causes fast file open/write operations. Or it slows down my PC so much. Anyway I cannot reproduce crash when AVG disabled. Although ProcMon shows that AVG access the file while enabled.

Finally, can somebody explain APC to me? Namely, can APC lead to double enter to the same function in the same thread?
I understood that it can from this text:
"An asynchronous procedure call (APC) is a function that executes asynchronously in the context of a particular thread. When an APC is queued to a thread, the system issues a software interrupt. The next time the thread is scheduled, it will run the APC function. "

I'm afraid to die without this understanding.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心房敞 2024-11-11 13:39:38

我不清楚您是否想要同时进行多个调用...您可以在 HeavyFunction 执行时禁用该按钮吗?

编辑

由于您似乎需要处理每个调用,因此您应该使用一个存储每个调用的队列,以及一个逐个执行它们的线程。

It is not clear to me whether you want many calls at the same time... you could just disabled the button while the heavyFunction executes?

EDIT

Since it seems you need every call handled, you should uses a Queue that stores every call, and a thread that executes them one by one.

与他有关 2024-11-11 13:39:38
class yourform {
   Queue<somedata> queue = new Queue<somedata>();
   Thread caller;   
   private bool Closing {get;set;}

   public yourform() {
     /// initcomponents bla bla
     Thread t = new Thread((ThreadStart)delegate() {
        while (!Closing) {
          lock (queue) {
             if (queue.Peek()) {
               somedata data = queue.Dequeue();
               HeavyFunction(data); // add invoke if required
             }
          }
        }
     }).Start();
     caller = t;
   }

   ~yourform() {
     Closing = true;
     caller.Join();
   }
   void clickEventHandler(object sender, EventArgs e) {
     somedata data = new somedata();
     queue.Queue(data);
   }
}

编辑:你没有标记 Visual basic 所以我没有注意到,但你可以使用在线 vb 到 c# 转换器...

class yourform {
   Queue<somedata> queue = new Queue<somedata>();
   Thread caller;   
   private bool Closing {get;set;}

   public yourform() {
     /// initcomponents bla bla
     Thread t = new Thread((ThreadStart)delegate() {
        while (!Closing) {
          lock (queue) {
             if (queue.Peek()) {
               somedata data = queue.Dequeue();
               HeavyFunction(data); // add invoke if required
             }
          }
        }
     }).Start();
     caller = t;
   }

   ~yourform() {
     Closing = true;
     caller.Join();
   }
   void clickEventHandler(object sender, EventArgs e) {
     somedata data = new somedata();
     queue.Queue(data);
   }
}

Edit: you did not tag Visual basic so I did not notice , but you can use an online vb to c# translator...

魔法少女 2024-11-11 13:39:38

您看到此行为是因为 Win32 消息是隐式可重入的。在 .NET 中尤其如此,因为每当您的 UI 线程阻塞时,运行时可能会代表您进行泵送。

解决此行为的正常方法是在执行长时间运行的事件处理程序时禁用控件,或者保留要运行的操作队列,而不是每次都启动另一个处理程序。

装甲运兵车是一种转移注意力的东西。它们可以在可警报等待中“借用”线程(.NET 运行时通常用于阻塞的 UI 线程),但 APC 不会调用 UI 事件处理程序(至少,我想不出任何会导致这种情况的情况) 。

You're seeing this behavior because Win32 messages are implicitly reentrant. This is particularly true in .NET because the runtime may pump on your behalf whenever your UI thread blocks.

The normal way to work around this behavior is to either disable the controls while the long-running event handler is executing, or keep a queue of actions to run instead of kicking off another handler each time.

APCs are a red herring. They can "borrow" a thread in an alertable wait (which the .NET runtime usually uses for blocked UI threads), but an APC will not invoke a UI event handler (at least, I cannot think of any situation that would cause this).

素食主义者 2024-11-11 13:39:38

From your comment you say you want the events to be processed one by one in the order they come in. This sounds like a queue. Have a look at this question: How to reuse threads in .NET 3.5 The accepted answer shows a worker queue implementation. If you use it with workerCount = 1 then you have a queue being processed by one thread and the events will be processed in the order they enter the queue.

如日中天 2024-11-11 13:39:38

您的 HeavyFunction 不能同时在同一线程上调用两次。单个线程一次只能执行一个函数——它必须在同一线程中再次调用之前返回。

我不确定发生了什么,但是如果您的鼠标单击事件处理程序正在创建一个新对象(使用 HeavyFunction),那么锁将无法帮助您。

HeavyFunction 每次都访问同一个文件吗?如果是这样,那么线程池也将无法工作,因为所有线程仍将尝试访问单个文件。

我认为最好的解决方案是使用 ChrisWise 建议的队列。

Your HeavyFunction cannot be called twice on the same thread at the same time. A single thread can only perform one function at a time -- it has to return before it is called again in the same thread.

I'm not sure what is going on, but if your mouse click event handler is creating a new object (with HeavyFunction), then a lock won't help you.

Does HeavyFunction access the same file each time? If so, then a thread pool won't work either because all the threads will still be trying to access a single file.

I think the best solution is to use a queue like ChrisWise suggests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文