看看下面的代码.假设这是整个类.我没有省略任何代码.这就是它的全部功能.
如果我在主程序循环中实例化这个类并不时调用myExample.Add(无论如何),我是否需要担心因为没有锁定Dequeue()和Enqueue()而导致的任何问题?
public class Example<T>
{
private Queue<T> q = new Queue<T>();
public Example()
{
new Thread(() =>
{
while (true)
{
if (this.q.Count > 0)
{
var item = this.q.Dequeue();
}
Thread.Sleep(1);
}
}).Start();
}
public void Add(T val)
{
this.q.Enqueue(val);
}
}
Run Code Online (Sandbox Code Playgroud)
如果在this.q.Dequeue()的同时调用this.q.Enqueue(val)会发生什么?
我正在研究一个数据绑定很大的Win.Forms应用程序,我发现了一些奇怪的行为.该应用程序具有单独的I/O线程,通过异步Web请求接收更新,然后将其发送到主/ GUI线程以处理和更新应用程序范围的数据存储(这些数据存储又可能与各种GUI元素绑定数据)等).Web请求另一端的服务器需要定期请求或会话超时.
我已经经历了几个处理线程问题等的尝试解决方案,并且我观察到以下行为:
如果我使用Control.Invoke将更新从I/O线程发送到主线程,并且此更新导致显示MessageBox,则主窗体的消息泵将停止,直到用户单击ok按钮.这也会阻止I/O线程继续最终导致服务器超时.
如果我使用Control.BeginInvoke从I/O线程(或多个)发送更新主线程的主窗体的消息泵并没有停止,但如果一个更新的处理导致了一个消息被显示,其余的处理在用户单击"确定"之前,该更新将暂停.由于I/O线程继续运行并且消息泵继续处理消息,因此可以在具有消息框的那个之前调用几个BeginInvoke用于更新.这导致无序更新,这是不可接受的.
I/O线程向阻塞队列添加更新(非常类似于在.NET中创建阻塞队列<T>).GUI线程使用Forms.Timer定期应用阻塞队列中的所有更新.此解决方案解决了阻塞I/O线程和更新顺序的问题,即下一次更新将永远不会开始,直到上一次完成.但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的.我希望主线程中的更新处理是事件驱动而不是轮询.
所以对我的问题.我应该怎么做到:
更新:见下面的解决方案
使用锁是否比使用本地(单个应用程序)信号灯具有更好的性能?
我从msdn阅读此博客:msdn上的生产者消费者解决方案
我不喜欢他们解决这个问题的方法,因为队列中总是剩下20个元素。
因此,我改为考虑使用仅在我的应用程序中可用的“信号量”(我只是不会在构造函数中命名),但是我不知道它将如何影响应用程序的性能。
有谁知道会影响性能吗?使用锁而不是“信号量”的其他考虑是什么?
我有几个线程,我怎么能暂停/恢复它们?
从重复的问题:
我如何暂停5个线程,并记住它们的状态.因为其中一个正在吃另一个正在思考等等
我正在处理一个图像处理应用程序,我的主线程上有两个线程:
1 - CameraThread,用于捕获网络摄像头中的图像并将其写入缓冲区
2 - ImageProcessingThread,从该缓冲区获取最新图像进行过滤.
这是多线程的原因是因为速度是至关重要的,我需要让CameraThread继续抓取图片并使ImageProcessingThread在处理上一张图像时准备好接收最新的捕获.
我的问题是找到一种快速且线程安全的方式来访问公共缓冲区,我认为理想情况下,它应该是一个三重缓冲区(图像[3]),这样如果ImageProcessingThread很慢,那么CameraThread可以继续写在另外两个图像上,反之亦然.
什么样的锁定机制最适合这种线程安全?
我查看了锁定语句,但似乎它会使一个线程阻塞 - 等待另一个完成,这将是三重缓冲点.
提前感谢任何想法或建议.
J.
我一直在使用这段代码作为一个阻塞的队列,Dequeue()直到一个元素入队.我已经在几个项目中使用了这段代码几年,所有项目都没有问题......直到现在.我现在正在写一些代码中的僵局,在调查问题时,我的"怀疑之眼"已经解决了这个问题BlockingQueue<T>.我无法证明这一点,所以我想我会问一些比我更聪明的人来审查潜在的问题.你能在这段代码中看到任何可能导致死锁的东西吗?
public class BlockingQueue<T>
{
private readonly Queue<T> _queue;
private readonly ManualResetEvent _event;
/// <summary>
/// Constructor
/// </summary>
public BlockingQueue()
{
_queue = new Queue<T>();
_event = new ManualResetEvent(false);
}
/// <summary>
/// Read-only property to get the size of the queue
/// </summary>
public int Size
{
get
{
int count;
lock (_queue)
{
count = _queue.Count;
}
return count;
}
}
/// <summary>
/// Enqueues element on the queue
/// </summary>
/// <param …Run Code Online (Sandbox Code Playgroud) 我有异步执行作业,每隔几分钟,有时Windows服务执行和以前的工作还没有完成一个窗口服务,使用线程有排队的新的工作方式,如果前一个处理不当完成,以便它开始运行时第一份工作完成了吗?
从多个线程获取消息到队列的最佳方法是什么,并且一次只有一个线程处理此队列的项目?
尝试断开多线程的活动时,我经常使用此模式.
我正在使用BlockingCollection,如下面的代码提取中所示:
// start this task in a static constructor
Task.Factory.StartNew(() => ProcessMultiUseQueueEntries(), TaskCreationOptions.LongRunning);
private static BlockingCollection<Tuple<XClientMsgExt, BOInfo, string, BOStatus>> _q = new BlockingCollection<Tuple<XClientMsgExt, BOInfo, string, BOStatus>>();
/// <summary>
/// queued - Simple mechanism that will log the fact that this user is sending an xMsg (FROM a user)
/// </summary>
public static void LogXMsgFromUser(XClientMsgExt xMsg)
{
_q.Add(new Tuple<XClientMsgExt, BOInfo, string, BOStatus>(xMsg, null, "", BOStatus.Ignore));
}
/// <summary>
/// queued - Simple mechanism that will log the data being …Run Code Online (Sandbox Code Playgroud) 生产者-消费者集合 [1] [2] 的所有 C# 实现似乎都有类似于以下内容的接口:
private Queue<T> items;
public void Produce(T item)
public T Consume()
Run Code Online (Sandbox Code Playgroud)
有没有像下面这样的实现?
private Queue<T> items;
public void Produce(T[] item)
public T[] Consume(int count)
Run Code Online (Sandbox Code Playgroud)
希望这能让我一次生产/消费不同数量的项目,而无需过多地锁定每个项目。这对于生产/消费大量项目似乎是必要的,但我没有找到任何实现的运气。
[1] C#生产者/消费者
我正在寻找像 ConcurrentQueue 这样的对象,如果队列为空,它允许我等待出队操作,因此我可以执行如下操作:
public static async Task ServiceLoop() {
var awaitedQueue = new AwaitedQueue<int>();
while (!cancelled) {
var item = await awaitableQueue.Dequeue();
Console.WriteLine(item);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经编写了以下类,但是如果在调用 Dequeue 和新的等待者入队之间将一个项目添加到队列中,则会发生可怕的事情。
public class AwaitedQueue<T> : IDisposable {
ConcurrentQueue<TaskCompletionSource<T>> awaiters = new ConcurrentQueue<TaskCompletionSource<T>>();
ConcurrentQueue<T> items = new ConcurrentQueue<T>();
public AwaitedQueue() { }
public void Enqueue(T item) {
if (!awaiters.TryDequeue(out TaskCompletionSource<T> awaiter)) {
this.items.Enqueue(item);
} else {
awaiter.SetResult(item);
}
}
public async Task<T> Dequeue() {
if (items.TryDequeue(out T item)) {
return item;
} else { …Run Code Online (Sandbox Code Playgroud) 可能重复:
在.NET中创建阻塞队列<T>?
我有典型的生产者和消费者线程问题.但是唯一的区别是允许生产者建立一个包含5个项目的缓冲区,之后它必须等到一些项目被消耗掉.
在c#中实现这一点的最佳解决方案是什么.目前我使用信号量实现它,但生产者似乎非常迅速地建立了超过100个项目的缓冲区.我没有语法来处理将缓冲区限制为5个项目.我正在考虑使用一个静态整数 - 让生产者增加它 - 当它达到5时,生产者进入睡眠状态.让消费者减少它并唤醒生产者.
我想要一个新线程内的计时器tick/elapsed事件.好像我不能使用Windows计时器.但是如果我使用Timers.Timer,它会为每个已发生的事件从线程池创建工作线程.有没有办法让这些事件发生在同一个线程中?
更新:
谢谢大家回答这个问题.
尽管如此,我在整个事情背后的意图可能听起来有些疯狂.我要你纠正我.当我试图解决这个问题时,这是我的想法(作为新手).我正在尝试每2秒执行一次任务.当我使用Timers.Timer时,它每2秒创建一个线程,我认为这是一个开销.
我的主线程和我的其他线程需要很多处理器的时间来执行他们的任务.因此,如果我可以避免创建这些线程,我将保存处理器的任何微秒,以便在每次计时器过去时为我的主线程和其他线程创建一个线程.
我进行了快速测试并比较了几个解决方案.每种情况下间隔1000毫秒.100个蜱虫.
解决方案1:等待/休眠的无限循环{00:01:42.0068344}
解决方案2:使用Brian的Synchronizer {00:01:42.4068573}
解决方案3:Timers.Timer,因为它是{00:01:42.4018571}
这应该告诉我2.0068344,2.4068573,2.4018571是在背景中浪费其他东西的时间,而不是100个刻度的1000毫秒的时间间隔.这应该意味着当solution1满足您的需求时,它是性能最佳的解决方案?
这也意味着虽然Brian的解决方案与一个线程同步,但它实际上是在后台创建线程.
请确认或纠正我.
c# ×12
multithreading ×11
.net ×6
locking ×2
queue ×2
.net-2.0 ×1
.net-3.5 ×1
asynchronous ×1
begininvoke ×1
buffering ×1
concurrency ×1
deadlock ×1
invoke ×1
messagebox ×1
semaphore ×1
timer ×1