- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现一个多线程库,该库将使用线程池同时运行任务。基本上它会从它收到的收集参数中将任务添加到线程池,然后等待直到正在处理的最后一个任务发送脉冲信号。我在早期的测试中取得了成功,但是当我想测试处理起来非常短的任务时遇到了一个奇怪的问题。不知何故,要么在等待命令在主线程中发生之前发送脉冲信号,要么发生其他事情,无论我为同步所做的努力如何,我都无法简单地看到。
为了解决我的问题,我已经实现了另一个“不太理想”的解决方案,因为我正在权衡潜在的性能优势,目前效果很好,但想知道为什么我的第一种方法在这种情况下不起作用首先是案例,尽管在性能方面两者之间没有太大区别。
为了说明,我在简化以下过程后添加了这两种解决方案。有人可以帮我指出哪里出了问题吗?
提前致谢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace TestcodeBenchmark
{
class Program
{
static int remainingTasks = 10000000;
static Stopwatch casioF91W = new Stopwatch();
static Random rg = new Random();
static readonly object waitObject = new object();
static void Main(string[] args)
{
TestLoop(30, remainingTasks);
Console.ReadKey();
}
private static void TestLoop(int loopCount, int remainingCountResetNumber)
{
for (int i = 0; i < loopCount; i++)
{
remainingTasks = remainingCountResetNumber;
//When this method is called it eventualy stuck at Monitor.Wait line
TestInterlocked();
remainingTasks = remainingCountResetNumber;
//When this method is called it processes stuff w/o any issues.
TestManualLock();
Console.WriteLine();
}
}
private static void TestInterlocked()
{
casioF91W.Restart();
//for (int i = 0; i < remainingTasks; i++)
//{
// ThreadPool.QueueUserWorkItem(delegate { TestInterlockedDecrement(); });
//}
int toStart = remainingTasks;
//for (int i = 0; i < remainingTasks; i++)
for (int i = 0; i < toStart; i++)
{
if (!ThreadPool.QueueUserWorkItem(delegate { TestInterlockedDecrement(); }))
Console.WriteLine("Queue failed");
}
//lock waitObject to be able to call Monitor.Wait
lock (waitObject)
{
//if waitObject is locked then no worker thread should be able to send a pulse signal
//however, if pulse signal was sent before locking here remainingTasks should be
//zero so don't wait if all tasks are processed already
if (remainingTasks != 0)
{
//release the lock on waitObject and wait pulse signal from the worker thread that
//finishes last task
Monitor.Wait(waitObject);
}
}
casioF91W.Stop();
Console.Write("Interlocked:{0}ms ", casioF91W.ElapsedMilliseconds);
}
private static void TestInterlockedDecrement()
{
//process task
//TestWork();
//Once processing finishes decrement 1 from remainingTasks using Interlocked.Decrement
//to make sure it is atomic and therefore thread safe. If resulting value is zero
//send pulse signal to wake main thread.
if (Interlocked.Decrement(ref remainingTasks) == 0)
{
//Acquire a lock on waitObject to be able to send pulse signal to main thread. If main
//thread acquired the lock earlier, this will wait until main thread releases it
lock (waitObject)
{
//send a pulse signal to main thread to continue
Monitor.PulseAll(waitObject);
}
}
}
private static void TestManualLock()
{
casioF91W.Restart();
//Acquire the lock on waitObject and don't release it until all items are added and
//Wait method is called. This will ensure wait method is called in main thread
//before any worker thread can send pulse signal by requiring worker threads to
//lock waitObject to be able to modify remainingTasks
lock (waitObject)
{
for (int i = 0; i < remainingTasks; i++)
{
ThreadPool.QueueUserWorkItem(delegate { TestManualDecrement(); });
}
Monitor.Wait(waitObject);
}
casioF91W.Stop();
Console.Write("ManualLock:{0}ms ", casioF91W.ElapsedMilliseconds);
}
private static void TestManualDecrement()
{
//TestWork();
//try to acquire lock on wait object.
lock (waitObject)
{
//if lock is acquired, decrement remaining tasks by and then check
//whether resulting value is zero.
if (--remainingTasks == 0)
{
//send a pulse signal to main thread to continue
Monitor.PulseAll(waitObject);
}
}
}
private static void TestWork()
{
//Uncomment following to simulate some work.
//int i = rg.Next(100, 110);
//for (int j = 0; j < i; j++)
//{
//}
}
}
}
最佳答案
当您开始您的任务时,您循环开始remainingTasks
任务。然而,当您接近 10000 时,一些任务已经完成并将此数字减少到 10000 以下,因此您没有启动正确数量的任务。如果我修改您的循环以保存应启动的任务数,代码将成功运行。 (请注意,您还应该检查 QueueUserWorkItem
的返回值。)
int toStart = remainingTasks;
for (int i = 0; i < toStart; i++)
{
if (!ThreadPool.QueueUserWorkItem(delegate { TestInterlockedDecrement(); }))
Console.WriteLine("Queue failed");
}
关于c# - 在多线程环境中使用 Interlocked.Decrement 以及 monitor.wait 和 monitor.pulse 时的错误行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14062137/
我是 iOS 开发新手。我正在解决的是如何在 iPhone 中运行我的应用程序时获取有关该应用程序的信息。 例如:当我在 Android 中开发时,我连接手机(使用净化模式)并打开 Android M
我仍然不确定这两个调用之间的区别。来自 MSDN, Monitor.Enter(Object) 获取指定对象的独占锁。 Monitor.Wait(Object) 释放对象上的锁并阻塞当前线程,直到它重
我是 GCP 的新手并且来自 Azure 背景。在 GCP 端是否有等效的“Azure Application Insights”用于监控应用程序? 让我用一个例子更清楚地解释我的用例:如果我有一个基
这是说明问题的最小代码: StringBuilder input = new StringBuilder(); void ToUpper() { lock (input) {
我在 ASP.NET 中有一个生产者-消费者场景。我设计了一个Producer 类,一个Consumer 类和一个用于保存共享对象并负责Producer 和Consumer 之间通信的类,我们称它为M
是否可以检测是否是同一个线程试图释放锁?我们在代码中有很多地方看起来像: try { try { if(!Monitor.TryEnter(obj, 2000))
我对并发编程有点陌生,正在尝试了解使用 Monitor.Pulse 和 Monitor.Wait 的好处。 MSDN 的例子如下: class MonitorSample { const in
如果您想在退出和清理对象时阻止执行某些代码块,是否可以使用锁来阻止执行? Monitor.TryEnter(cleanupLock, ref acquiredLock); TryEnter 可用于确保
Monitor.Enter 和 Monitor.Exit 设计为从同一线程调用。但是,如果我需要在与获得的线程不同的线程中释放锁怎么办? 例如:有共享资源和使用该资源的异步操作。该操作以 BeginO
Monitor.PulseAll 通知队列中的所有等待线程。 Monitor.Pulse 通知等待队列中的一个线程。 (下一个等待线程) 只有下一个线程(一个线程)才能获取锁。那有什么区别呢? 什么时
我正在尝试在我的 terraform 代码库中集成对 sshd 进程的 Datadog 监视器检查,但我收到 datadog_monitor.host_is_up2: error updating m
这里的问题是:如果获取对象独占锁的线程(例如通过使用 Monitor.Enter)终止,是否会神奇地释放该对象的独占锁?如果那是真的,那么假设我们从另一个线程调用 Monitor.Exit - 因为我
我正在研究 .NET 中的 Monitor 类,所以我找到了一段似乎可以正常工作的代码,但是当我将它循环一段时间时,它会抛出 OutOfMemoryException。 我在具有 8 GB RAM 的
ECMA-335 规范规定如下: *获取锁(System.Threading.Monitor.Enter 或进入同步方法)应隐式执行 volatile 读取操作,并释放锁(System.Threadi
我在 dll 中使用 OmniThreadLibrary 2.09,主应用程序和 dll 使用相同的 SimpleShareMem 内存管理器。 我用以下代码创建了自己的监视器: FMonitor
我正在使用 R 包 monitoR并收到一条我无法理解的错误消息。 我正在尝试使用 dbUploadTemplate 命令将关联模板列表(“bithTemps”)上传到 MySQL 数据库(“noh”
我想我遗漏了一些关于 Monitor.Enter 和 Monitor.TryEnter 正确行为的信息。这是我编写的一段代码,用于将问题与其余代码分开: object lockObj = new ob
我正在尝试实现一个多线程库,该库将使用线程池同时运行任务。基本上它会从它收到的收集参数中将任务添加到线程池,然后等待直到正在处理的最后一个任务发送脉冲信号。我在早期的测试中取得了成功,但是当我想测试处
我想用redis lua来实现monitor命令,而不是redis-cli monitor。但我不知道怎么办。 redis.call('monitor') 不起作用。 最佳答案 您不能从 Redis
根据语言规范,lock(obj) statement; 会被编译为: object lockObj = obj; // (the langspec doesn't mention this var,
我是一名优秀的程序员,十分优秀!