【发布时间】:2017-07-20 00:33:56
【问题描述】:
在 C# 项目中,我有一个类 (ThreadSpawner),它产生线程并在列表 (_runningJobs) 中跟踪它们。如果线程已完成,则应从该列表中删除它们。
到目前为止,我使用 Thread.IsAlive 属性进行了尝试,但这不起作用,因为它似乎总是正确的并且永远不会变为错误。
我想在 IsFinished 方法中检查的是线程是否已经死亡并且不再运行,我认为当 DoJob 方法离开时会自动发生。
任何提示如何检查它们?
不知道哪个线程状态说线程不存在了……
我的(示例)代码:
public class ThreadSpawner {
private List<SpawnedThread> _runningJobs;
private bool _isStopRequested;
private int maxRunningJobs = 3;
private Thread _thread;
public ThreadSpawner() {
_runningJobs = new List<SpawnedThread>();
_isStopRequested = false;
_thread = null;
}
public void Start() {
_thread = new Thread(DoJob);
_thread.Start();
}
public void DoJob() {
while(!_isStopRequested) {
//check if there are finished jobs in the list and remove them if they are finished
for (int i = _runningJobs.Count-1; i >= 0; i--) {
if (_runningJobs.ElementAt(i).IsFinished()) {
_runningJobs.RemoveAt(i);
}
}
//spawn threads if possible and required
if (_runningJobs.Count less maxRunningJobs && ShouldThreadBeSpawned()) {
SpawnedThread st = new SpawnedThread();
_runningJobs.Add(st);
st.Start();
}
Thread.Sleep(100);
}
}
public void Stop() {
_isStopRequested = true;
for (int i = 0; i less _runningJobs.Count; i++) {
_runningJobs.ElementAt(i).Stop();
}
}
public bool IsFinished() {
return _thread == null || ( _runningJobs.Count == 0 && _thread.IsAlive);
}
private bool ShouldThreadBeSpawned() {
return true; //actually whatever the criteria says
}
}
public class SpawnedThread {
private bool _isStopRequested;
private Thread _thread;
public ThreadSpawner() {
_isStopRequested = false;
_thread = null;
}
public void Start() {
_thread = new Thread(DoJob);
_thread.Start();
}
public void DoJob() {
// does whatever it should do
// and leaves the DoJob method
// and I assumed when this method is left IsAlive would become false but it doesn't
}
public void Stop() {
_isStopRequested = true;
}
public bool IsFinished() {
return _thread == null || _thread.IsAlive;
}
}
提炼问题
如何启动线程/任务以跟踪正在运行的线程/任务并能够通过代码停止它们(可以为每个线程/任务调用一些代码以停止包含的进程)?
更多细节
整个系统用于 (.NET Core) Windows 服务(请参阅我的其他问题)。 Windows 服务启动 ThreadSpawner。 ThreadSpawner 查询数据库以查找要执行的作业。对于每个作业,它都会产生一个 SpawnedThread。该线程从数据库中查询另一组数据,通过网络获取一些文件。然后 SpawnedThread 启动(一个接一个)一些调用可执行文件的进程,并将结果从一个可执行文件传递给下一个可执行文件调用。然后将结果文件放回去并将结果存储在数据库中。
除了当 Windows 服务停止时我不知道如何判断线程是否正在运行并以一种也停止进程的方式终止生成的线程的问题之外,一切正常。 (同样的机制也用于检查被调用的 exe 是否挂起,并用其进程和 SpawnedThread 杀死挂起的 exe。
为什么我没有使用过 ThreadPool 和 ThreadPool.QueueUserWorkItem
首先我有。但是我无法跟踪哪些线程正在运行并且无法以也停止进程的方式杀死它们。无论是windows服务停止的情况,还是检测到外部exe挂起的情况。
为什么我没有使用任务
我们(我的团队)从未与他们合作过,因此决定采用线程。我很高兴看到有关如何处理任务的建议。
【问题讨论】:
-
您使用线程而不是任务是否有特殊原因?因为线程是一种不好的做法,而且任务更容易检查...
-
这听起来非常适合使用
Tasks 和/或 TPL 进行完全重写,其中内置支持取消和状态 (for example)。对于初学者来说,维护像_isStopRequested这样的布尔值需要您研究内存障碍,以了解为什么简单的分配不起作用。这不好玩。 -
您还可以使用回调函数(比如说 ThreadCompleted)并在线程功能结束时调用此函数。在此函数中,您可以编写代码以从正在运行的作业列表中删除。
-
@MIdrees 你的意思是,像任务一样,具有手动回调和每次创建新线程的开销
-
@monty 即使您出于某种原因不想使用任务,您也不应该使用原始线程。创建线程有开销。所有 Windows 应用程序都可以利用预先分配的、可重用的线程池。使用ThreadPool.QueueUserWorkItem 在线程池线程上执行函数。这就是默认执行任务的方式
标签: c# multithreading