5

我面临的问题是,我在一些线程之间共享了一个 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 平台在这个领域表现良好。

此致,

弗里德里希

4

5 回答 5

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);
}

}

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

于 2010-02-03T16:39:42.037 回答
3

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

由于正确性问题比性能问题更重要,而且同步原语可能非常棘手,因此我会先使用该Mutex解决方案,如果结果是一个问题,则寻找另一个解决方案。

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

于 2010-02-03T16:31:03.337 回答
2

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

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

于 2010-02-03T16:31:20.590 回答
1

I would go with the Mutex() route until you are sure that you need to go with something more exotic.

Also, consider using a Monitor (or the c# lock statement -- same thing), if you are concerned about weight. The lock/Monitor performs better than a Mutex. However, it is not visible outside of your process (but then, you aren't creating a named Mutex, so it looks as if you don't need it to be visible outside your process).

于 2010-02-03T17:07:45.013 回答
0

如果您碰巧使用的是 .Net 4,您还可以查看新的 SpinLock 结构

于 2010-02-03T17:11:58.610 回答