多线程行为

本文关键字:多线程 | 更新日期: 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的调用不是原子的,也没有被锁定,因此线程可以同时更改计数。