多线程行为

时间:2012-02-07 18:22:12

标签: c# .net multithreading

我有以下代码来帮助我理解多线程,它的目的是创建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

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

你的最后一个线程调用e.Set()作为它的最后一行,它释放主线程的WaitAll(),但并不意味着最后一个工作线程退出{{ 1}}方法。偶尔,即使在最后一个工作程序从CreatWorkBetter调用退出方法之前,主线程也会唤醒并计算活动工作线程的数量。

所以我的最后一段代表:

这是理解线程的关键 - 除非使用同步构造来控制每个线程的状态,否则不能对方法中的其他线程的相对状态做出假设。

答案 1 :(得分:1)

您遇到两个线程已终止且一个线程在e.Set()结束时调用PooledFunc但尚未终止的情况。同时主线程的WaitAll(resetEvent)已经返回,主线程正在调用ListAvailableThreads()

答案 2 :(得分:0)

我没有在C#中尝试过很多线程,但我在Java中做得不错。我认为对GetAvailableThreads的调用不是原子的,也不是锁定因此线程可以同时改变计数。