我有以下代码来帮助我理解多线程,它的目的是创建3个带有调试代码的后台工作线程来显示线程使用/可用性。 现在代码看起来不错,但我有时会得到意想不到的结果。
致电代码:
static void Main(string[] args)
{
ThreadPool.CreatWorkBetter();
Console.ReadLine();
}
实施守则:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using t = System.Threading;
namespace CSharpConcepts
{
public static class ThreadPool
{
private static t.ManualResetEvent[] resetEvent;
public static void CreatWorkBetter()
{
Console.WriteLine("Start");
ListAvailableThreads();
resetEvent = new t.ManualResetEvent[3];
resetEvent[0] = new t.ManualResetEvent(false);
resetEvent[1] = new t.ManualResetEvent(false);
resetEvent[2] = new t.ManualResetEvent(false);
t.ThreadPool.QueueUserWorkItem(
new t.WaitCallback(delegate(object state)
{
PooledFunc("Stage 1", resetEvent[0]);
}));
t.ThreadPool.QueueUserWorkItem(
new t.WaitCallback(delegate(object state)
{
PooledFunc("Stage 2", resetEvent[1]);
}));
t.ThreadPool.QueueUserWorkItem(
new t.WaitCallback(delegate(object state)
{
PooledFunc("Stage 3", resetEvent[2]);
}));
t.WaitHandle.WaitAll(resetEvent);
Console.WriteLine("Finished");
ListAvailableThreads();
}
static void PooledFunc(object state, t.ManualResetEvent e)
{
Console.WriteLine("Processing request '{0}'", (string)state);
// Simulation of processing time
t.Thread.Sleep(2000);
Console.WriteLine("Request processed");
ListAvailableThreads();
e.Set();
}
public static void ListAvailableThreads()
{
int avlThreads, avlToAsynThreads;
t.ThreadPool.GetAvailableThreads(out avlThreads, out avlToAsynThreads);
string message = string.Format("Processed request: {3}, From ThreadPool :{0} ,Thread Id :{1},Free Threads :{2}",t.Thread.CurrentThread.IsThreadPoolThread,t.Thread.CurrentThread.ManagedThreadId,avlThreads,t.Thread.CurrentThread.ThreadState);
Console.WriteLine(message);
}
}
}
我期望结果是明智的,而且大部分时间我得到它(免费线程显示的关键线回到1023是我真正想看到的):
启动已处理的请求:正在运行,来自ThreadPool:False,线程ID :1,自由线程:1023处理请求'阶段1'处理请求 '阶段2'处理请求'阶段3'请求已处理已处理 请求:Background,From ThreadPool:True,Thread Id:4,Free Threads :1020请求处理已处理的请求:后台,来自ThreadPool :True,Thread Id:3,Free Threads:1021 Request Processed Processed 请求:Background,From ThreadPool:True,Thread Id:5,Free Threads :1022 已完成处理的请求:正在运行,来自ThreadPool:错误,线程ID:1,自由线程:1023
但是,我有时会看到显示1022的免费线程,我希望它是1023,因为3个线程已完成工作所以它们应该已经返回到线程池:
启动已处理的请求:正在运行,来自ThreadPool:False,线程ID :1,自由线程:1023处理请求'阶段1'处理请求 '阶段2'处理请求'阶段3'请求已处理已处理 请求:Background,From ThreadPool:True,Thread Id:3,Free Threads :1020请求处理已处理的请求:后台,来自ThreadPool :True,Thread Id:4,Free Threads:1020 Request Processed Processed 请求:Background,From ThreadPool:True,Thread Id:5,Free Threads :1022 已完成处理的请求:正在运行,来自ThreadPool:错误,线程ID:1,自由线程:1022
有什么想法吗?
答案 0 :(得分:2)
你的最后一个线程调用e.Set()
作为它的最后一行,它释放主线程的WaitAll()
,但并不意味着最后一个工作线程退出{{ 1}}方法。偶尔,即使在最后一个工作程序从CreatWorkBetter
调用退出方法之前,主线程也会唤醒并计算活动工作线程的数量。
所以我的最后一段代表:
这是理解线程的关键 - 除非使用同步构造来控制每个线程的状态,否则不能对方法中的其他线程的相对状态做出假设。
答案 1 :(得分:1)
您遇到两个线程已终止且一个线程在e.Set()
结束时调用PooledFunc
但尚未终止的情况。同时主线程的WaitAll(resetEvent)
已经返回,主线程正在调用ListAvailableThreads()
。
答案 2 :(得分:0)
我没有在C#中尝试过很多线程,但我在Java中做得不错。我认为对GetAvailableThreads的调用不是原子的,也不是锁定因此线程可以同时改变计数。