我有一个Windows服务,它使用生产者/消费者队列模型,多个工作线程处理队列中的任务.这些任务可以运行很长时间,如果不是几小时,则按很多分钟的顺序运行,并且不涉及循环.
我的问题是关于处理服务停止以在这些工作线程上优雅地结束处理的最佳方法.我在另一个SO问题中读到,使用thread.Abort()是设计不良的标志,但似乎服务OnStop()方法在服务终止之前只有有限的时间完成.我可以在catchA中为ThreadAbortException做足够的清理(没有不一致状态的危险)所以在工作线程上调用thread.Abort()对我来说似乎没问题.是吗?有哪些替代方案?
我有一个需要大量初始化的对象(在一台强壮的机器上1-2秒).虽然一旦初始化,只需要大约20毫秒来做一个典型的"工作"
为了防止每次应用程序想要使用它时重新初始化它(可能是每秒50次,或者在典型使用中几分钟都没有),我决定给它一个工作,并让它运行在它自己的线程上,检查在que中是否有任何工作.但是,我不完全确定如何创建一个无论是否有工作运行的线程.
这就是我到目前为止所做的任何批评都受到欢迎
private void DoWork()
{
while (true)
{
if (JobQue.Count > 0)
{
// do work on JobQue.Dequeue()
}
else
{
System.Threading.Thread.Sleep(50);
}
}
}
Run Code Online (Sandbox Code Playgroud)
经过深思熟虑:我以为我可能需要优先杀死这个线程让它永远运行,所以我想我会添加一个告诉线程结束的Job类型.关于如何结束这样的线程的任何想法也赞赏.
我有一个先前的问题,我提供了我的解决方案; 但是,ConcurrentQueue<T>因为我在.Net 3.5上,所以我没有访问权限.我需要Queue<T>允许并发.我读了这个问题,如果一个项目不在队列中并且线程方法试图使项目出列,则似乎存在问题.
我现在的任务是确定是否可以派生自己的并发队列类.这就是我想出的:
public sealed class ConcurrentQueue : Queue<DataTable>
{
public event EventHandler<TableQueuedEventArgs> TableQueued;
private ICollection que;
new public void Enqueue(DataTable Table)
{
lock (que.SyncRoot)
{
base.Enqueue(Table);
}
OnTableQueued(new TableQueuedEventArgs(Dequeue()));
}
// this is where I think I will have a problem...
new public DataTable Dequeue()
{
DataTable table;
lock (que.SyncRoot)
{
table = base.Dequeue();
}
return table;
}
public void OnTableQueued(TableQueuedEventArgs table)
{
EventHandler<TableQueuedEventArgs> handler = TableQueued;
if …Run Code Online (Sandbox Code Playgroud) 我正在考虑在C#中实现通用的生产者/消费者对+处理队列的想法.我们的想法是你可以创建实现适当的IProducer和IConsumer接口(提供默认实现)的对象,它们将主要由委托组成,将它们传递给QueueProcessor类实例,告诉它你想要多少个消费者,然后去.
但我对自己说,"自我,这肯定已经做过了."
因此,没有人知道的好,一般实施在C#中的生产者/消费者模式(VB.Net是好的,太)?我正在寻找的基本要求:
或者如果没有,哪些陷阱阻止了它,你对如何实现它有任何想法吗?
我需要用户能够扫描一系列项目,并且每个项目都打印出x个标签.我目前正在尝试使用后台工作程序来完成此操作,但我遇到了一个问题,他们正在如此快速地扫描项目,并且有很多标签要为后台工作人员窒息的每个项目打印.这就是我为每次扫描生成后台工作线程的方法,因为在打印大量标签时会发生争用.
private void RunPrintWorker()
{
if (printWorker.IsBusy)
{
printWorker = new BackgroundWorker();
printWorker.DoWork += new DoWorkEventHandler(printWorker_DoWork);
printWorker.RunWorkerAsync();
}
else
printWorker.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)
我没有得到后台工作者的任何例外,它似乎没有足够快地创建线程.我是使用多线程的新手,所以有人能指出我做错的方向吗?
谢谢.
编辑:感谢大家的建议和阅读材料,这应该真的有帮助.打印标签的顺序并不重要,因为它们扫描速度非常快,标签也只打印到一台打印机上.在我实现启动并运行后,我将标记答案.
编辑:奥斯汀,下面是我如何设置我的打印方法.在我刚刚在RunPrintWorker方法中调用LabelPrinter.PrintLabels之前.现在我正在重做这个,我无法弄清楚要传递给SizeQueue方法的内容.我应该将新创建的打印文档传递给它吗?
public class LabelPrinter
{
private int CurrentCount = 0;
private List<int> _selectedRows = new List<int>();
public List<int> SelectedRows
{
get { return _selectedRows; }
set { _selectedRows = value; }
}
private string _selectedTemplate;
public string SelectedTemplate
{
get { return _selectedTemplate; }
set { _selectedTemplate = value; }
}
private string _templateDirectory = string.Empty; …Run Code Online (Sandbox Code Playgroud) 我的问题是,下面包含的类对于单读者单编写器队列类线程安全吗?这种队列称为无锁,即使队列已填满也会阻塞.数据结构的灵感来自Marc Gravell在StackOverflow 上实现的阻塞队列.
结构的要点是允许单个线程将数据写入缓冲区,而另一个线程则读取数据.所有这些都需要尽快发生.
Herb Sutter在DDJ的文章中描述了类似的数据结构,但实现是在C++中.另一个区别是我使用了一个vanilla链表,我使用了一个链表的数组.
我不是仅仅包含一段代码,而是将所有内容与允许的开源许可证(MIT许可证1.0)一起包含,以防任何人发现它有用,并且想要使用它(原样或修改).
这与Stack Overflow上有关如何创建阻塞并发队列的其他问题有关(请参阅在.NET中创建blockinq队列和在.NET中创建线程安全阻塞队列).
这是代码:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
namespace CollectionSandbox
{
/// This is a single reader / singler writer buffered queue implemented
/// with (almost) no locks. This implementation will block only if filled
/// up. The implementation is a linked-list of arrays.
/// It was inspired by the desire to create a non-blocking version
/// of the …Run Code Online (Sandbox Code Playgroud) 我正在编写一个需要处理大型文本文件的应用程序(用逗号分隔的几种不同类型的记录 - 我没有权力或倾向更改数据存储格式)。它读入记录(通常是按顺序读取文件中的所有记录,但并非总是如此),然后将每个记录的数据传递给一些处理。
现在这部分应用程序是单线程的(读取记录,处理它,读取下一条记录等)我认为在一个线程中读取队列中的记录并在另一个线程中处理它们可能更有效线程在小块中或在它们可用时。
我不知道如何开始编写类似的程序,包括必要的数据结构或如何正确实现多线程。任何人都可以提供任何指示,或提供有关我如何提高性能的其他建议吗?
我如何使用c#中的队列?我想要一个将数据排入队列的线程,另一个线程将数据从队列中取出.那些线程应该同时运行.
可能吗?
我正在研究一个数据绑定很大的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线程和更新顺序的问题,即下一次更新将永远不会开始,直到上一次完成.但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的.我希望主线程中的更新处理是事件驱动而不是轮询.
所以对我的问题.我应该怎么做到:
更新:见下面的解决方案
c# ×8
.net ×6
.net-3.5 ×1
algorithm ×1
begininvoke ×1
invoke ×1
messagebox ×1
printing ×1
queue ×1