互锁与互斥,扩大规模的问题

时间:2010-02-03 16:18:39

标签: c# multithreading mutex scale

我遇到了问题,我在某些线程之间共享了一个C#(.NET)对象。线程可能会用另一个线程替换该对象。使用异步框架从TCP / IP连接中唤醒线程。

序列:

主题(等待连接) - >异步回调 - >做一些线程安全的事情 - > 访问共享对象 - >做一些线程安全的事情。

1。解决方案互斥:

Object sharedObject = new Object();
Mutex objectMutex = new Mutex();

void threadCallback()
{
  Object newObject = new Object();

  // some processing

  objectMutex.lock();
  // do exchange sharedObject with newObject if needed
  // very little processing here
  objectMutex.unlock();

  // some processing
}

2。解决方案联锁

Object sharedObject = new Object();
int usingSharedObject = 0;

void threadCallback()
{
  Object newObject = new Object();

  // some processing

  // poll until we lock
  while(1 == Interlocked.Exchange(ref usingSharedObject , 1))
  {
    // do exchange sharedObject with newObject if needed
    // very little processing here
    Interlocked.Exchange(ref usingSharedObject , 0); // free lock
  }

  // some processing
}

什么更快,更好地扩展?

我希望只要没有多个线程同时进行轮询,第二个解决方案就会更快。第二种解决方案甚至可以随机休眠,以便轮询不会占用任何处理时间。如果我确实需要处理大量的TCP / IP连接,那么第一个解决方案看起来更干净。由于我在关于TCP / IP处理的锁定部分中进行的处理很少,是否会出现任何向上扩展的问题?

如何在threadCallback()函数的开头创建对象。

在我的C ++背景中,我总是在这种情况下使用内存池,因为我必须使用安全的.NET有一种快速创建新对象的方法,或者.NET平台在这个领域中表现良好。

致以最诚挚的问候,

弗里德里希

5 个答案:

答案 0 :(得分:5)

您的互锁操作不正确。旋转锁通常看起来像这样:

int sharedLock = 0;

void callback()
{

do {
 int existingState = Interlocked.CompareExchange(ref sharedLock, 1, 0);
 if (0 == existingState) {
  break;
 }
} while (true);

try
{
 // operate on the shared state
}
finally
{
 int existingState = Interlocked.Exchange(ref sharedLock, 0);
 Debug.Assert (1 == existingState);
}

}

至于使用一个与另一个的原因,它主要取决于持有锁时所完成的操作类型。非常短的操作(短算术加/减法,简单状态标志改变等)更适合自旋锁。在spinlock下不能进行繁重的操作(分配,IO访问),所以它们必须在真正的互斥锁下完成。

答案 1 :(得分:3)

乍一看,您的2个示例可能不相同。在我看来,使用Interlocked.Exchange()的投票解决方案将进入处理循环,而其他内容已声明“自制信号量”,并且如果自制则会跳过交换sharedObjectnewObject信号量声称。 (除非我误解了某些事情,这很可能)。

由于正确性问题更重要的是性能问题和同步原语可能非常难以正确使用我首先使用Mutex解决方案并查看另一个解决方案,如果它证明是一个问题。

Win32添加了一个带旋转计数的互斥对象,以充分利用您在这里尝试做的两个世界(我认为)。但是,据我所知,它还没有在.NET框架中公开过。

答案 2 :(得分:2)

查看第二个示例的工作方式,看来如果没有获取锁定,您将退出,跳过代码的重要部分。

Mutex方法更容易理解,我没有遇到任何性能问题。

答案 3 :(得分:1)

我会选择Mutex()路线,直到你确定你需要使用更具异国情调的东西。

另外,如果你担心体重,可以考虑使用Monitor(或c#lock语句 - 同样的事情)。锁定/监视器的性能优于互斥锁。但是,它在您的进程之外是不可见的(但是,您没有创建一个已命名的Mutex,因此看起来好像您不需要它在进程外可见)。

答案 4 :(得分:0)

如果您正在使用.Net 4,您还可以查看新的SpinLock结构