C# 加入以StartNew()开始的线程
当使用StartNew()方法在新线程上启动进程时,我需要弄清楚如何在同一线程中对该对象进行另一次调用(我假设这是某种连接操作?) 下面的例子被简化,以说明我正在尝试做的内容。我很清楚它严重缺乏基本的并发性考虑。但是我不想用这些逻辑来模糊代码,所以请原谅我 下面的控制台应用程序显示了我正在尝试实现的目标。假设在StartNew()调用中创建了一个ID为9976的新线程,并在其中调用了该方法。我还希望在线程9976上对文件系统监视程序更改事件处理程序中的ProcessImmediate()进行后续调用。目前,该调用将共享用于文件系统监视程序更改事件的同一线程 可以这样做吗?如果可以,怎么做C# 加入以StartNew()开始的线程,c#,.net,multithreading,C#,.net,Multithreading,当使用StartNew()方法在新线程上启动进程时,我需要弄清楚如何在同一线程中对该对象进行另一次调用(我假设这是某种连接操作?) 下面的例子被简化,以说明我正在尝试做的内容。我很清楚它严重缺乏基本的并发性考虑。但是我不想用这些逻辑来模糊代码,所以请原谅我 下面的控制台应用程序显示了我正在尝试实现的目标。假设在StartNew()调用中创建了一个ID为9976的新线程,并在其中调用了该方法。我还希望在线程9976上对文件系统监视程序更改事件处理程序中的ProcessImmediate()进行后续
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
public void Run()
{
_activity = new Activity();
// start activity on a new thread
Task.Factory.StartNew(() => _activity.Go());
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "c:\temp";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity
{
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
System.Threading.Thread.Sleep(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
DoSomethingInteresting();
}
public bool Stop { get; set; }
}
}
*更新*
谢谢你的精彩回复。我采纳了Mike的建议,并将其应用于我的控制台应用程序。下面是完整的工作代码,其中还包括取消令牌的使用。我把这篇文章发出去,以防别人发现它有用
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
runner.Stop();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
private CancellationTokenSource _cts = new CancellationTokenSource();
public void Stop() { _cts.Cancel(); }
public void Run()
{
_activity = new Activity();
// start activity on a new thread
var task = new Task(() => _activity.Go(_cts.Token), _cts.Token, TaskCreationOptions.LongRunning);
task.Start();
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "C:\\Temp\\FileSystemWatcherPath";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go(CancellationToken ct)
{
Thread.CurrentThread.Name = "Go";
while (!ct.IsCancellationRequested)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(5000);
}
Console.WriteLine("Exiting");
}
protected virtual void DoSomethingInteresting()
{
Console.WriteLine(string.Format("Doing Something Interesting on thread {0}", Thread.CurrentThread.ManagedThreadId));
}
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
_processing.Set();
}
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
}
首先,如果创建的任务无法快速完成,则应使用
TaskCreationOptions.LongRunning
。其次,使用AutoResetEvent
向等待的线程发出唤醒信号。请注意,下面的ProcessImmediate
将在另一个线程上完成运行DoSomethingInteresting
之前返回。例如:
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
用户mike提供了一个更好的解决方案,当您希望立即调用相同的方法时,该解决方案将是合适的。如果你想立即调用不同的方法,我将扩展mike的答案来实现这一点
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
private ConcurrentQueue<Action> actionsToProcess = new ConcurrentQueue<Action>();
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
while(!actionsToProcess.IsEmpty)
{
Action action;
if(actionsToProcess.TryDeque(out action))
action();
}
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate(Action action)
{
actionsToProcess.Enqueue(action);
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
使用系统线程;
公共课堂活动:IDisposable
{
私有自动恢复事件_processing=新自动恢复事件(false);
私有ConcurrentQueue actionsToProcess=新ConcurrentQueue();
公开作废Go()
{
当(!停止)
{
//出于本例的目的,神奇地假设调用ProcessImmediate时未调用它
DoSomethingInteresting();
_《处理》,WaitOne(2000年);
而(!actionsToProcess.IsEmpty)
{
行动;
if(actionsToProcess.TryDeque(out操作))
动作();
}
}
}
受保护的虚拟void DoSomethingInteresting(){}
公共无效处理立即(操作)
{
ActionStopProcess.Enqueue(操作);
_processing.Set();
}
公共布尔停止{get;set;}
公共空间处置()
{
if(_processing!=null)
{
_processing.Dispose();
_处理=空;
}
}
}
要在同一线程上执行不同的方法,可以使用消息循环来分派传入的请求。一个简单的选择是使用反应式扩展,并“递归地”调度Go()函数——如果同时调度了一个不同的操作,它将在下一个Go()操作之前被处理
以下是一个示例:
class Loop
: IDisposable
{
IScheduler scheduler = new EventLoopScheduler();
MultipleAssignmentDisposable stopper = new MultipleAssignmentDisposable();
public Loop()
{
Next();
}
void Next()
{
if (!stopper.IsDisposed)
stopper.Disposable = scheduler.Schedule(Handler);
}
void Handler()
{
Thread.Sleep(1000);
Console.WriteLine("Handler: {0}", Thread.CurrentThread.ManagedThreadId);
Next();
}
public void Notify()
{
scheduler.Schedule(() =>
{
Console.WriteLine("Notify: {0}", Thread.CurrentThread.ManagedThreadId);
});
}
public void Dispose()
{
stopper.Dispose();
}
}
static void Main(string[] args)
{
using (var l = new Loop())
{
Console.WriteLine("Press 'q' to quit.");
while (Console.ReadKey().Key != ConsoleKey.Q)
l.Notify();
}
}
如何更改FileSystemWatcher\u Changed方法以确保ProcessImmediate调用与Go在同一线程上进行?@John我不确定我是否理解您的要求。
ProcessImmediate
的内容已移动到另一个线程。在ProcessImmediate
中是否还有其他要在另一个线程上调用的内容?没关系,是的,您的示例正是我想要的。我已经用最终的控制台代码更新了我的问题,以防其他人有类似的问题。如果您使用的是mike的代码,则无需修改任何内容。那应该work@John:我试图用Notify()方法来说明这一点:您可以通过调用scheduler.Schedule(DoSomethingInteresting)将调用排队,以便在EventLoopThread上执行。