C#多线程问题求解答

runerback 2016-08-26 04:32:42
在一个类里开几个工作线程,并且在类被释放之前(调用Dispose方法)都保持运行。线程方法里面使用while(true)来保持运行,为了节省开销用AutoResetEvent控制。
整个流程是在一个项目里看到的,我把关键部分的代码提出来:

public class ThreadsTest : IDisposable
{
public ThreadsTest()
{
this.threads = new List<Thread>();
this.Initialized = false;
this.Disposing = false;
this.blocker = new AutoResetEvent(false);

int processerCount = Environment.ProcessorCount > 0 ?
Environment.ProcessorCount : 1;
for (int i = 0; i < processerCount; i++)
{
Thread thread = new Thread(this.ThreadFunc);
thread.Name = string.Format("Threads test worker thread {0}", i);
thread.IsBackground = true;
thread.Priority = ThreadPriority.Lowest;
thread.Start();
this.threads.Add(thread);
}
this.Initialized = true;
this.blocker.Set();
}

public bool Initialized { get; private set; }
public bool Disposing { get; private set; }

private List<Thread> threads;
private AutoResetEvent blocker;
public event Action Disposed;

private void ThreadFunc()
{
if (!this.Initialized)
{
this.blocker.WaitOne();
}
while (true)
{
if (this.Disposing)
{
break;
}
Console.WriteLine("{0} running.", Thread.CurrentThread.Name);
this.blocker.WaitOne();
}
if (this.Disposed != null)
{
this.Disposed();
}
}

public void Dispose()
{
this.Disposing = true;
this.blocker.Set();
}
}

本来原来是没有手动释放功能的,我自己加上后,在执行Dispose方法之后,我看了下Thread List里面的线程,只有一个被释放了(Alive为false),其它的还在继续运行。
所以想知道AutoResetEvent 是不是只对一个线程起作用,还有这种情况下如何设计才能“准确”释放掉所有相关的后台工作线程。
...全文
226 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
runerback 2016-08-29
  • 打赏
  • 举报
回复
看来要自己重新设计了
runerback 2016-08-29
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
当你从比较优化的多线程程序设计角度去使用线程,那么你的代码基本上90%以上都是多余的了。
我也觉得是,线程用完释放掉就好了,他这个调试的时候也让人觉得莫名其妙
runerback 2016-08-29
  • 打赏
  • 举报
回复
引用 3 楼 shingoscar 的回复:
手动控制的叫ManualResetEvent https://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent.aspx 可见程序员学习英语的重要性
这俩我都知道,但是没仔细看过有啥区别
bb_Sam 2016-08-27
  • 打赏
  • 举报
回复
AutoResetEvent 使用可以看看这个文档 https://blog.gkarch.com/threading/part2.html#autoresetevent
  • 打赏
  • 举报
回复
当你从比较优化的多线程程序设计角度去使用线程,那么你的代码基本上90%以上都是多余的了。你的大的方面问题其实也就不存在了。你根本不会这样去设计程序。 有些人,不分析任务的细节,先上来说“反正我启动进程时先开n个线程,将来就能提高效率”,这纯粹是滥用线程的一个幼稚的借口。跟这样的人你无法具体讨论并发多线程的流程的设计细节,因为他不跟你讨论设计细节本身,他脑子里就是先弄固定个数的线程在那里死循环着、轮询着某些队列。他不知道异步多线程的算法程序要设计为响应式、事件驱动的才高效。他就是一味去轮询。
  • 打赏
  • 举报
回复
从程序设计上说,不要滥用线程,线程通常应该一瞬间(几百毫秒)即结束任务。滥用线程就会让CPU“发烫”、内存多好非数G,假装繁荣其实是“令人发指”地空耗资源。例如说,当你想异步地干嘛的时候(利润就是想并发地执行多个 Console.WriteLine 语句),那么你应该这个时候才用到多线程,想用2个、10个、20个都有可能,瞬间(几毫秒)之后异步执行的任务就全都结束了。而不是想当然地弄 processerCount 个线程在那里死循环着。 如果你担心线程调度资源耗费问题,那就使用系统线程池来分配线程(而不要 new Thread)。 单从你的语句上来说,AutoResetEvent 就是只让一个阻塞的线程通过的。这个是比较底层的问题,你自己看看文档即可。
Poopaye 2016-08-26
  • 打赏
  • 举报
回复
手动控制的叫ManualResetEvent https://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent.aspx 可见程序员学习英语的重要性
Poopaye 2016-08-26
  • 打赏
  • 举报
回复
名字就叫AutoResetEvent
runerback 2016-08-26
  • 打赏
  • 举报
回复
测试之后发现情况比我想的要差

public class ThreadsTestClass
{
private ThreadsTest test;

public void Do()
{
this.test = new ThreadsTest();
this.test.Disposed += this.ThreadsDisposed;
Task.Factory.StartNew(this.TestMethod).Wait();
Console.WriteLine("Test Completed.");
}

private void TestMethod()
{
Console.WriteLine("Press enter to finish");
Console.ReadLine();

this.test.Dispose();
}

private void ThreadsDisposed()
{
this.test.Disposed -= this.ThreadsDisposed;
foreach (var thread in this.test.Threads)
{
Console.WriteLine("{0} alive: {1}", thread.Name, thread.IsAlive);
}
this.test = null;
}
}

结果成了这样

试了好几次才正常一次

开的线程全都在运行

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧