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






4.44/5 (22投票s)
2003年7月11日
2分钟阅读

213993

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 个线程。