多线程行为
本文关键字:多线程 | 更新日期: 2023-09-27 18:22:50
我有以下代码来帮助我理解多线程,其目的是创建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的关键线是我真正希望看到的):
启动已处理的请求:正在运行,来自线程池:False,线程Id:1,可用线程:1023正在处理请求"阶段1"正在处理请求"第2阶段"处理请求"第3阶段"处理的请求已处理request:后台,来自线程池:True,线程Id:4,可用线程:1020已处理请求已处理请求:后台,来自线程池:True,线程Id:3,可用线程:1021已处理请求已处理request:后台,来自线程池:True,线程Id:5,可用线程:1022已完成处理的请求:正在运行,来自线程池:False,线程Id:1,可用线程:1023
然而,我有时会看到空闲线程显示1022,我希望是1023,因为有3个线程已经完成了工作,所以它们应该返回到线程池:
启动已处理的请求:正在运行,来自线程池:False,线程Id:1,可用线程:1023正在处理请求"阶段1"正在处理请求"第2阶段"处理请求"第3阶段"处理的请求已处理request:后台,来自线程池:True,线程Id:3,可用线程:1020已处理请求已处理请求:后台,来自线程池:True,线程Id:4,可用线程:1020已处理请求request:后台,来自线程池:True,线程Id:5,可用线程:1022已完成处理的请求:正在运行,来自线程池:False,线程Id:1,可用线程:1022
有什么想法吗?
您的最后一个线程调用e.Set()
作为它的最后一行,这将从它的WaitAll()
释放主线程,但这并不意味着最后一个工作线程已经退出CreatWorkBetter
方法。偶尔,主线程会在最后一个工作线程从e.Set()
调用退出该方法之前唤醒并计算活动工作线程的数量。
所以我的最后一段是:
这是理解线程的关键——除非使用同步结构来控制每个线程的状态,否则不能从一个方法中对其他线程的相对状态进行假设。
您遇到的情况是,您的两个线程已经终止,而一个线程在PooledFunc
结束时调用了e.Set()
,但尚未终止。同时主线程的WaitAll(resetEvent)
已经返回并且主线程正在调用ListAvailableThreads()
。
我在C#中没有尝试过太多线程,但在Java中做得不错。我认为对GetAvailableThreads的调用不是原子的,也没有被锁定,因此线程可以同时更改计数。