我已经阅读了关于此的文档,我想我明白了.一个AutoResetEvent当代码经过复位event.WaitOne(),但ManualResetEvent没有.
它是否正确?
考虑一个Console应用程序,它在一个单独的线程中启动一些服务.它需要做的就是等待用户按Ctrl + C将其关闭.
以下哪项是更好的方法?
static ManualResetEvent _quitEvent = new ManualResetEvent(false);
static void Main() {
Console.CancelKeyPress += (sender, eArgs) => {
_quitEvent.Set();
eArgs.Cancel = true;
};
// kick off asynchronous stuff
_quitEvent.WaitOne();
// cleanup/shutdown and quit
}
Run Code Online (Sandbox Code Playgroud)
或者,使用Thread.Sleep(1):
static bool _quitFlag = false;
static void Main() {
Console.CancelKeyPress += delegate {
_quitFlag = true;
};
// kick off asynchronous stuff
while (!_quitFlag) {
Thread.Sleep(1);
}
// cleanup/shutdown and quit
}
Run Code Online (Sandbox Code Playgroud) ManualResetEventSlim状态的MSDN文档
ManualResetEvent与预期等待时间非常短的情况相比,您可以使用此类获得更好的性能.
"很短"多久了?在什么时候使用内核对象的好处ManualResetEvent超过了实例化它的开销?
我实现了以下后台处理线程,其中Jobs是Queue<T>:
static void WorkThread()
{
while (working)
{
var job;
lock (Jobs)
{
if (Jobs.Count > 0)
job = Jobs.Dequeue();
}
if (job == null)
{
Thread.Sleep(1);
}
else
{
// [snip]: Process job.
}
}
}
Run Code Online (Sandbox Code Playgroud)
这产生正在进入作业时之间的noticable延迟,当他们实际上开始运行(作业批次在一旦进入,而每个工作只是[比较]小)的延迟是不是一个大问题,但我开始思考这个问题,并做了以下改变:
static ManualResetEvent _workerWait = new ManualResetEvent(false);
// ...
if (job == null)
{
lock (_workerWait)
{
_workerWait.Reset();
}
_workerWait.WaitOne();
}
Run Code Online (Sandbox Code Playgroud)
线程添加作业现在锁定_workerWait并_workerWait.Set()在完成添加作业时调用.这个解决方案(貌似)立即开始处理工作,延迟完全消失.
我的问题部分是"为什么会发生这种情况?",被认为Thread.Sleep(int)可以比你指定的更长时间地睡眠,部分是"如何ManualResetEvent实现这种性能水平?".
编辑:由于有人询问了排队项目的功能,现在它和目前的完整系统一起.
public void RunTriggers(string data)
{
lock …Run Code Online (Sandbox Code Playgroud) 我觉得我应该知道答案,但无论如何我都会问,以防万一我犯了一个潜在的灾难性错误.
以下代码按预期执行,没有错误/异常:
static void Main(string[] args)
{
ManualResetEvent flag = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(s =>
{
flag.WaitOne();
Console.WriteLine("Work Item 1 Executed");
});
ThreadPool.QueueUserWorkItem(s =>
{
flag.WaitOne();
Console.WriteLine("Work Item 2 Executed");
});
Thread.Sleep(1000);
flag.Set();
flag.Close();
Console.WriteLine("Finished");
}
Run Code Online (Sandbox Code Playgroud)
当然,正如多线程代码的情况一样,成功的测试并不能证明这实际上是线程安全的.如果我Close之前提出的话,测试也会成功Set,即使文档明确指出在a之后尝试做任何事情Close都会导致未定义的行为.
我的问题是,当我调用该ManualResetEvent.Set方法时,是否保证在将控制权返回给调用者之前发出所有等待线程的信号?换句话说,假设我能够保证不会再进一步调用,在这里关闭句柄是否安全,或者在某些情况下这个代码可能会阻止一些服务员发出信号或导致一个?WaitOneObjectDisposedException
该文档仅表示Set将其置于"信号状态" - 它似乎没有任何关于服务员何时会获得该信号的声明,所以我想确定.
我不熟悉ManualResetEvent的用法?
它与线程有关吗?它做什么以及何时使用?
在这里我得到了一个使用ManualResetEvent的代码,但我只是不明白它的作用?
这是代码
public class Doc : SomeInterfaceFromTheDll
{
private readonly IVersion version; // An interface from the DLL.
private readonly ManualResetEvent _complete = new ManualResetEvent(false);
private bool downloadSuccessful;
// ...
public bool Download()
{
this.version.DownloadFile(this);
// Wait for the event to be signalled...
_complete.WaitOne();
return this.downloadSuccessful;
}
public void Completed(short reason)
{
Trace.WriteLine(string.Format("Notify.Completed({0})", reason));
this.downloadSuccessful = reason == 0;
// Signal that the download is complete
_complete.Set();
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
的意义是什么 _complete.WaitOne(); & _complete.Set(); ?
任何人都可以给我一些小样本代码,其中包含ManualResetEvent类的用法.
寻找好的讨论和使用ManualResetEvent?谢谢
我不确定采用哪种策略......我专注于我的操作完成,但我也想将性能问题保持在最低限度......有一种名为Execute()的方法必须等待(同步运行)直到操作完成.此操作发生在另一个线程上.有两种方法可以实现同样的事情......
通过使用ManualResetEvent
void Execute()
{
taskHandle = new ManualResetEvent(false);
.
.
//delegate task to another thread
.
.
taskHandle.WaitOne();
}
Run Code Online (Sandbox Code Playgroud)
通过使用简单的while构造
void Execute()
{
.
.
//delegate task to another thread
.
.
while (!JobCompleted)
Thread.Sleep(1000);
}
Run Code Online (Sandbox Code Playgroud)
我应采用两种方法中的哪一种......为什么?
编辑:
Q2.如果我在构造时只是空了怎么办?有什么不同...?
while(!JobCompleted);
Run Code Online (Sandbox Code Playgroud)
编辑:(之前我收集过的东西)
http://www.yoda.arachsys.com/csharp/threads/waithandles.shtml - 这篇文章说手动复制比较慢,因为它们离开了托管代码并重新进入......
我正在编写一个包含几个线程的程序,每个程序都有一个while循环,直到用户指定它应该停止.我想到了退出循环的几种方法,以及随后的线程,并在下面概述了这些方法.
问题
以下是方法.
该bool方法
最初,我已经声明了一个bool并且刚刚声明循环运行直到用户将bool设置为false : while(running) { Thread.Sleep(10); /*do work*/ }. 然后我思索是否完全是线程安全的.如果编译器进行了一些优化并将bool移动到寄存器,该怎么办?在这种情况下,线程会看到bool的不同值.因此,我使用volatile关键字标记bool 以避免编译器优化.
该ManualResetEvent方法
我的下一个方法是创建一个ManualResetEvent,并且只是说,当WaitOne()为false时bool运行:while(!mre.WaitOne(10)) {/*do work*/}.这将阻塞10ms,然后一遍又一遍地运行循环,直到我们这样做mre.Set()并且循环退出.
该CancellationToken方法
我还没有尝试过这种方法,但是我读了几个人们喜欢用这种方式取消线程的地方.它显然是线程安全的.可以定义一个CancellationTokenSource,调用它cts,然后传递cts.Token给新线程运行的方法,并使用if语句检查是否已请求取消:while(!token.IsCancellationRequested) { Thread.Sleep(10); /*do work*/ }
更新1:
我发现了一篇类似的帖子,得出的结论是该MRE方法明显慢于该CancellationToken方法.有关完整信息,请参阅此处:停止线程,ManualResetEvent,volatile boolean或cancellationToken
更新2:
当谈到将这种bool方法与其他两种方法进行比较时,Eric Lippert在这里有一个很好的答案:AutoResetEvent vs. boolean来阻止一个线程
更新3:
我找到了另一条相关的信息.取消取消后,取消权限无法重置.因此,当您只想暂时取消循环,以后再次启动它时,它并不理想.为此,MRE可能会更好(因为您可以根据自己的内容设置和重置).
c# multithreading manualresetevent cancellation cancellation-token
我遇到了在锁定manualResetEvent实例时导致的死锁.我无法弄清楚如何解决它.我将不胜感激任何帮助.
我在不同线程执行的类中有2个方法:
private ManualResetEvent _event = new ManualResetEvent (true);
private void process(){
...
lock(_event){
_event.WaitOne();
...
}
}
internal void Stop(){
_event.Reset();
lock(_event){
...
}
}
Run Code Online (Sandbox Code Playgroud)
第一个线程启动了锁,并在_event.WaitOne()中被阻止;
socond线程执行了_event.Reset()行; 并在尝试执行锁定(_event)时被阻止.
我认为当在WaitOne上阻塞线程1时,应该释放锁.我想我错了.我不知道如何解决它.顺便说一句 - 我添加了锁,因为锁块中的代码应该在两个线程中同步.
再次感谢,并为长篇文章感到抱歉.
这是对WinForms RichTextBox的跟进
:如何在TextChanged上执行格式化?
我有一个带有RichTextBox的Winforms应用程序,该应用程序会自动突出显示所述框的内容.因为大型文档的格式化需要很长时间,10秒或更长时间,我已经设置了BackgroundWorker来重新格式化RichTextBox.它遍历文本并执行一系列这些:
rtb.Select(start, length);
rtb.SelectionColor = color;
Run Code Online (Sandbox Code Playgroud)
在这样做的同时,UI仍然保持响应.
BackgroundWorker从TextChanged事件开始.像这样:
private ManualResetEvent wantFormat = new ManualResetEvent(false);
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
xpathDoc = null;
nav = null;
_lastChangeInText = System.DateTime.Now;
if (this.richTextBox1.Text.Length == 0) return;
wantFormat.Set();
}
Run Code Online (Sandbox Code Playgroud)
后台worker方法如下所示:
private void DoBackgroundColorizing(object sender, DoWorkEventArgs e)
{
do
{
wantFormat.WaitOne();
wantFormat.Reset();
while (moreToRead())
{
rtb.Invoke(new Action<int,int,Color>(this.SetTextColor,
new object[] { start, length, color} ) ;
}
} while (true);
}
private void SetTextColor(int start, int length, System.Drawing.Color color) …Run Code Online (Sandbox Code Playgroud) manualresetevent ×10
c# ×7
.net ×4
sleep ×3
cancellation ×1
deadlock ×1
richtextbox ×1
winforms ×1