关于锁性能/使用的2个问题

Tho*_*mas 1 c# multithreading locking

在服务器应用程序上,我需要为每个连接的客户端分配一个唯一的ID,所以我这样做:

private short GetFreeID()
{
    lock (this.mUsedPlayerIDsSynchronization)
    {
        for (short I = 1; I < 500; I++)
        {
            if (ClientIDPool[I] == false)
            {
                ClientIDPool[I] = true;
                return I;
            }
        }
        return -1;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的第一个问题:能否更有效地完成,我的意思是更好的表现?我在这里读过,我们应该学会编写没有锁的代码.我还在那里阅读了一些原子操作还有其他选择.第二个问题:如果我想锁定整个课程以便不允许在其中进行任何更改,该怎么办?例如:一个客户端将更新第二个客户端数据,我可以锁定它被绝对阻止的整个第二个客户端类吗?我仍然认为"锁定"只会确保其片段中的代码当时只被一个线程输入,所以我不知道"lock(client2)"是否导致该类中的任何内容都无法更改,直到此锁定为止释放.

Jon*_*eet 11

锁定通常是最简单的方法,这是非常重要的.通常,如果有更有效的处理方式并不重要,只要你有清晰的代码并且它的表现足够好.

但是,更高效的方法是生成随机GUID,或者如果您确实要重用ID,则LinkedList使用未使用ID 的"池"(例如a ).然后,您可以非常快速地从池中取出,并在完成后将ID返回池中(再次快速).

另外,如果你真的只需要一个整数,它不具备成为一个低之一,你可以有它从0开始,您只需每次增加一个静态变量-你可以做到这一点,而无需使用锁Interlocked.Increment,你应该希望.我怀疑你会耗尽64位整数,例如:)

至于你的第二个问题:是的,锁是建议性的.如果类中的所有内容在更改任何字段之前取出相同的锁(并且字段是私有的)那么这会阻止其他代码行为不端......但是每一段代码需要取出锁.

编辑:如果你真的只需要一个整数,我仍然建议只使用Interlocked.Increment- 即使你的流量增加1000倍,你可以使用64位整数.但是,如果您想重用ID,那么我建议创建一个新类型来表示"池".给多少计数器已经创建的,所以,如果你用完了,你可以指定一个新的项目.然后只将可用的存储在a中Queue<int>,LinkedList<int>或者Stack<int>(你使用它并不重要).假设您可以信任自己的代码以合理地返回ID,您可以使API简单如下:

int AllocateID()
void ReturnID(int id)
Run Code Online (Sandbox Code Playgroud)

AllocateID将检查池是否为空,如果是,则分配一个新ID.否则,它只会删除池中的第一个条目并返回该条目.ReturnID只会将指定的ID添加到池中.