1. Semaphore
Semaphore
是一个.NET的线程同步对象,可以用来控制对资源的并行访问数量。Semaphore 在计算机科学中是一个很重要的概念,用于解决多线程编程中的各种问题。
基本上,Semaphore 是一个计数器,表示一个特定的资源可以被多少个线程同时访问。当一个线程试图进入一个受 Semaphore 控制的区块时,如果当前的计数大于零,则此线程可以继续执行,并且计数器会减一。如果计数器为零,则该线程将被阻塞,直到其他线程释放资源(计数器增加)。
在.NET中,你可以使用 System.Threading.Semaphore
类实现这个功能。
以下是一个简单的示例:
代码语言:javascript复制// Creates a Semaphore object that can support up to three threads, with an initial count of zero threads.
Semaphore sem = new Semaphore(0, 3);
// Increment the semaphore count by three, allowing three threads to enter.
sem.Release(3);
// The current thread tries to enter the semaphore. If the count is greater than zero, it succeeds and the count is decremented by one.
sem.WaitOne();
Semaphore跨进程使用
使用 Semaphore
实现进程间同步的一种方式是使用具有特定名称的 Semaphore
。在一个进程中创建命名的 Semaphore
后,可以在其他进程中通过名称打开并使用该 Semaphore
。
以下是创建和使用命名 Semaphore
的示例:
进程1:
代码语言:javascript复制// 创建一个具有最大计数 3 和初始计数 0 的命名 Semaphore
Semaphore semaphore = new Semaphore(0, 3, "MySemaphore");
// 允许三个线程或进程访问资源
semaphore.Release(3);
// ... 进行其他工作 ...
// 不再需要 Semaphore 时关闭它
semaphore.Close();
进程2:
代码语言:javascript复制// 在另一个进程中打开已经存在的命名 Semaphore
Semaphore existingSemaphore;
try
{
existingSemaphore = Semaphore.OpenExisting("MySemaphore");
}
catch(System.Threading.WaitHandleCannotBeOpenedException)
{
Console.WriteLine("The named semaphore does not exist.");
return;
}
// 尝试进入 semaphore. 如果计数器大于零,则成功并将计数器减一
existingSemaphore.WaitOne();
// ... 进行工作 ...
// 完成工作后,释放访问权,以便其他等待的线程或进程可以进入
existingSemaphore.Release();
// ... 进行其他工作 ...
// 不再需要 Semaphore 时关闭它
existingSemaphore.Close();
这样便实现了两个或更多进程之间的同步。每个需要访问共享资源的进程都会调用 WaitOne()
方法。如果 Semaphore
的当前计数大于零,那么线程就可以继续执行并将 Semaphore
的计数减一。如果计数为零,那么此线程将被阻塞,直到其他线程调用 Release()
方法增加计数。
2. SemaphoreSlim
SemaphoreSlim
是.NET 4.5引入的一个轻量级版本的 Semaphore,它主要用于在同一台机器上的任务和线程间进行同步,在性能上比 Semaphore
要好,但不能跨进程使用。
除了性能提升之外,SemaphoreSlim
还提供了异步支持,通过 WaitAsync
方法可以非阻塞地等待进入 Semaphore。
以下是一个简单的使用示例:
代码语言:javascript复制// Creates a SemaphoreSlim object that can support up to three threads, with an initial count of zero threads.
SemaphoreSlim semSlim = new SemaphoreSlim(0, 3);
// Increment the semaphore count by three, allowing three tasks or threads to enter.
semSlim.Release(3);
// The current task or thread tries to enter the semaphore.
// If the count is greater than zero, it succeeds and the count is decremented by one.
await semSlim.WaitAsync();
在使用完 Semaphore
或 SemaphoreSlim
后,应调用 Release
方法以便其它等待的线程或任务可以进入。
Task中使用SemaphoreSlim
在这个示例中,SemaphoreSlim 被用来限制在任意时刻只有一个 Task 可以进入临界区。其他尝试进入临界区的 Task 将被挂起,直到当前 Task 执行完毕并释放 SemaphoreSlim。
代码语言:javascript复制SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10; i )
{
tasks.Add(Task.Run(async () =>
{
await semaphore.WaitAsync();
try
{
// Critical section.
Console.WriteLine("Task {0} in critical section.", Task.CurrentId);
await Task.Delay(1000); // Simulate some work.
}
finally
{
Console.WriteLine("Task {0} leaving critical section.", Task.CurrentId);
semaphore.Release();
}
}));
}
await Task.WhenAll(tasks);
Semaphore 和 SemaphoreSlim 区别
SemaphoreSlim
有更好的性能和内存效率,但只能在同一进程中使用。Semaphore
可以跨进程使用,但性能和内存效率不如SemaphoreSlim
。SemaphoreSlim
支持异步操作。