C# 如何限制并发进程的数量?

C# 如何限制并发进程的数量?,c#,C#,我的情况如下: 我有一个只能启动固定次数(少于50次)的应用程序 由于业务需求,不允许使用单独的中心流程来管理其他流程。(即,如果一个只涉及应用程序流程的好解决方案仍然可以接受) 我使用C#开发应用程序,因此首选托管解决方案 我必须处理“意外”情况,例如使用TaskManager可以终止进程 我正在考虑使用系统范围互斥的解决方案。然而,它不能很好地经受“意外”情况,因为它会留下“被抛弃的”互斥体。如果这是一个好方法,我可以问一下“忽略”已放弃的互斥锁有什么好处吗?一种方法是查询进程列表并计算当前

我的情况如下:

  • 我有一个只能启动固定次数(少于50次)的应用程序
  • 由于业务需求,不允许使用单独的中心流程来管理其他流程。(即,如果一个只涉及应用程序流程的好解决方案仍然可以接受)
  • 我使用C#开发应用程序,因此首选托管解决方案
  • 我必须处理“意外”情况,例如使用TaskManager可以终止进程

  • 我正在考虑使用系统范围互斥的解决方案。然而,它不能很好地经受“意外”情况,因为它会留下“被抛弃的”互斥体。如果这是一个好方法,我可以问一下“忽略”已放弃的互斥锁有什么好处吗?

    一种方法是查询进程列表并计算当前活动的实例数。另一种更复杂的方法是广播UDP并计算响应数。我将此模式用于与作业处理器相关的分布式场景


    Colby Africa

    您可以使用共享内存段,并在每次打开应用程序时递增计数,在关闭应用程序时递减计数。一种更简单的方法可能是使用您在问题中提到的进程间信号量。

    当进程通过“意外”事件(如任务管理器进程终止)终止时,它应该抛出ThreadAbortException。你真的应该尝试用某种try/finally来包装你的互斥锁,这样你就可以在线程中止时释放它


    我不是100%确定这是真的,但是没有什么方法可以应对这样的情况。

    扩展流程列表方法,使用C#可能看起来像这样:

    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Text;
    using System.Management;
    
    namespace WmiProc
    {
        class Program
        {
            static void Main(string[] args)
            {
                ManagementScope ms = new System.Management.ManagementScope(
                    @"\\myserver\root\cimv2");
    
                var oq = new System.Management.ObjectQuery(
                    "SELECT * FROM Win32_Process where Name='myprocname'");
                ManagementObjectSearcher query1 = new ManagementObjectSearcher(ms, oq);
                ManagementObjectCollection procsCollection = query1.Get();
                Console.WriteLine("process count:{0}", procsCollection.Count);
            }
        }
    }
    
    编辑:启动时间会有一些分离,因此不太可能让太多的进程同时运行。您必须测试环境中的特定行为


    也许您可以定期检查单独(长时间运行)进程的进程计数,并根据某些标准(例如最新)终止多余的进程。

    好的,您可以使用命名的互斥实例

    对互斥体使用个人命名方案,请求此名称并检查已创建具有此名称的互斥体的结果

    如果将命名方案与增量元素一起使用,则可以尝试使用增量元素的所有互斥体名称,并按如下方式计算创建了多少互斥体

    在处理释放的互斥体方面仍然需要一些改进,但这似乎微不足道

    class Program
    {
        private static Mutex mutex = null;
    
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
    
            int count = Program.CheckInstanceCount();
            Console.WriteLine("This is instance {0} running.", count);
            Console.Read();
        }
    
        static void CurrentDomain_ProcessExit(object sender, EventArgs e)
        {
            Program.mutex.ReleaseMutex();
            Program.mutex.Close();
        }
    
        private static int CheckInstanceCount()
        {
            int result = 0;
            bool created = false;
    
            for (int i = 0; i < 50; i++)
            {
                /* try to create a mutex with this name, 
                 * if it does exist, another instance 
                 * of this program is running
                 */
                mutex = new Mutex(true, string.Concat(AppDomain.CurrentDomain.FriendlyName, i.ToString()), out created);
                if (created)
                {
                    // this instance is instance #i currently running
                    result = i;
                    break;
                }
            }
            return result;
        }
    }
    
    类程序
    {
    私有静态互斥量Mutex=null;
    静态void Main(字符串[]参数)
    {
    AppDomain.CurrentDomain.ProcessExit+=新事件处理程序(CurrentDomain\u ProcessExit);
    int count=Program.CheckInstanceCount();
    WriteLine(“这是实例{0}正在运行。”,count);
    Console.Read();
    }
    静态无效CurrentDomain_ProcessExit(对象发送方,事件参数e)
    {
    Program.mutex.ReleaseMutex();
    Program.mutex.Close();
    }
    私有静态int CheckInstanceCount()
    {
    int结果=0;
    bool-created=false;
    对于(int i=0;i<50;i++)
    {
    /*尝试创建具有此名称的互斥对象,
    *如果它确实存在,请选择另一个实例
    *这个程序正在运行
    */
    互斥量=新互斥量(true,string.Concat(AppDomain.CurrentDomain.FriendlyName,i.ToString()),已创建完毕);
    如果(已创建)
    {
    //此实例是当前正在运行的实例#i
    结果=i;
    打破
    }
    }
    返回结果;
    }
    }
    
    我无法为上述答案添加注释,但通过阅读上述答案和注释,您似乎可以将互斥锁与流程实例检查结合起来

    // You can use any System wide mutual exclusion mechanism here
    bool waitAndLockMutex();
    void unlockMutex();
    
    // returns the number of processes who use the specified command
    int getProcessCount();
    
    void main() {
        try {
            waitAndLockMutex();
            if (getProcessCount() > MAX_ALLOWED)
                return;
    
            doUsualWork();
    
        } finally {
            unlockMutex();
        }
    }
    
    请注意,上面的代码仅用于说明目的,声明的函数调用的主体可以使用.NET轻松编写

    编辑:

    如果不想对感兴趣的进程进行计数,可以使用全局互斥。不确定.NET是否公开了这一点。但要点是,您可以获取所有互斥体,直到达到最大值。在此过程中,如果您获得了一个尚未创建或已放弃的互斥体,那么您可以继续并让该过程启动,否则退出,并显示超过最大值计数

    void main() {
        for (int i = 0; i < MAX; ++i) {
            int status = TryToAcquireMutex("mutex" + i);
            continue if (status == locked);
            if (status == success || status == WAIT_ABANDONED) {
                doUsusalWork();
            }
        }
    }
    
    void main(){
    对于(int i=0;i
    我曾想过使用共享内存方法,但如果进程终止,我无法减少该数字(进程意外死亡,没有代码执行,或者可能有代码执行?)使用广播UDP方法,这是否意味着“保护”不严格?我的意思是,如果进程忙于处理某些事情,并且回答得太晚,是否会导致我对活动进程的计算不准确?我也会想到进程列表。确保即使忙也能响应的方法是让另一个线程睡在套接字上等待广播。侦听器线程在接收到广播并作出响应时唤醒。确保侦听器是一个后台线程,因此如果主工作线程死亡,它将死亡!关于此查询流程方法,如果多个流程同时启动,此方法是否会导致大多数流程未通过检查(因为对于每个流程,他们都会“相信”许多流程已经启动)?感谢您的建议。我也尝试过这种方法,唯一的问题是,如果我杀死TaskManager以前启动的进程,那么.NET会抛出废弃的MutexException。有底片吗