65.9K
CodeProject 正在变化。 阅读更多。
Home

一个简单的进程内信号量(使用 C#)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (22投票s)

2003年7月11日

2分钟阅读

viewsIcon

213993

downloadIcon

3677

创建一个信号量,以限制在进程中访问资源的线程数量。

引言

很多时候,我们受到限制,只能使用受控数量的线程来访问可用的资源。本文描述了如何创建一个信号量(在单个进程内部使用)并控制线程数量。如果您想使用全局信号量来控制跨进程的线程,那么您必须使用 Windows 信号量。

信号量代码

Semaphore.cs 文件包含控制线程的代码,并且可以自行在任何项目中单独使用。构造函数将要控制的线程数量作为参数,并创建一个互斥锁数组,用于阻塞线程。使用 WaitHandle.WaitAny() 来等待此互斥锁数组。

        // array of mutex to block the threads
        private Mutex[] m_mutex;

        // place holder to store thread to mutex mapping
        private Thread[] m_threadIds;

        // number of threads allowed to access the resources
        private int m_threadLimit;

        // contructor creates the mutexes
        public Semaphore(int threadLimit)
        {
            m_threadLimit = threadLimit;
            m_mutex = new Mutex[m_threadLimit];
            m_threadIds = new Thread[m_threadLimit];
            for (int i=0; i<m_threadLimit; i++)
            {
                m_mutex[i] = new Mutex();
                m_threadIds[i] = null;
            }
        }

重要的是将当前线程映射到它正在阻塞的互斥锁,这将在调用信号量的 Semaphore.Release() 时用于释放互斥锁。使用一个简单的 Thread 数组将调用线程映射到线程锁定的互斥锁,方法是在下面的代码中调用 Thread.CurrentThread

        // if there is a timeout then WaitHandle.WaitTimeout is returned
        // calling thread should check for this
        public int Wait()
        {
            int index = WaitHandle.WaitAny(m_mutex);
            if (index != WaitHandle.WaitTimeout)
                m_threadIds[index] = Thread.CurrentThread;
            return index;
        }

当在信号量上调用释放时,将在数组中搜索锁定线程,并对相应的互斥锁调用 ReleaseMutex() 以允许下一个线程。

        // release the mutex locked by the thread
        public void Release()
        {
            for (int i=0; i<m_threadLimits; i++)
            {
                if (m_threadIds[i] == Thread.CurrentThread)
                {
                    m_mutex[i].ReleaseMutex();
                    break;
                }
            }
        }

测试代码

为了测试信号量代码,创建了一个简单的表单和一个按钮,其目的 - 在按下时创建线程。创建了一个静态信号量实例,以供表单中的所有线程共享。

       private static Semaphore m_semaphore = new Semaphore(5);

创建了一个静态方法,用于启动线程。该方法等待信号量。在任何时候,只有提及的最大线程数才能通过这一点,以显示消息框。

        public static void TestThread()
        {
            m_semaphore.Wait();
            MessageBox.Show("I am on a new thread");
            m_semaphore.Release();
        }

按钮单击事件被捕获,并且每次按下按钮都会创建一个新线程,如下所示

        private void StartThread_Click(object sender, System.EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(TestThread));
            t.Start();
        }

当我们按下按钮时,我们可以看到只有 5 个消息框显示,这表明信号量只允许 5 个线程。

使用 C# 的一个简单的进程内信号量 - CodeProject - 代码之家
© . All rights reserved.