Skip to main content
added 143 characters in body
Source Link
Pierre Menard
  • 2.2k
  • 15
  • 30

Since your lock only needs to protect the member variables you mutate, you can scope it to just that if/else block where you make your modifications. You do use _sequence one additional time when generating the return value, but that could use a local copy acquired while the lock is held. So the main thing you are moving outside the lock block is the call to GetTicks().

If you can figure out how to implement this with Interlocked functions, that's going to be the best performance. I'm not an expert, but I don't think you can do it directly, you would probably have to pack your sequence and generation into a single long. A ReaderWriterLockSlim offers more functionality than you need - you have no readers - so it's likely not optimal. You'll want to measure, but out of all the locks I'd guess you'd get the best performance from a SpinLock.

There's a whole use case you mention where these things are allocated per-thread, where presumably you don't want to pay for any thread safety overhead. I would suggest moving the code that requires locking into a separate virtual function with no thread-safety mechanisms, and making a subclass that overrides the implementation in a thread-safe way. This could be as simple as:

protected override long Increment()
{
    lock (_genlock)
    {
         return base.Increment();
    }
}

Since your lock only needs to protect the member variables you mutate, you can scope it to just that if/else block where you make your modifications. You do use _sequence one additional time when generating the return value, but that could use a local copy acquired while the lock is held. So the main thing you are moving outside the lock block is the call to GetTicks().

If you can figure out how to implement this with Interlocked functions, that's going to be the best performance. A ReaderWriterLockSlim offers more functionality than you need - you have no readers - so it's likely not optimal. You'll want to measure, but out of all the locks I'd guess you'd get the best performance from a SpinLock.

There's a whole use case you mention where these things are allocated per-thread, where presumably you don't want to pay for any thread safety overhead. I would suggest moving the code that requires locking into a separate virtual function with no thread-safety mechanisms, and making a subclass that overrides the implementation in a thread-safe way. This could be as simple as:

protected override long Increment()
{
    lock (_genlock)
    {
         return base.Increment();
    }
}

Since your lock only needs to protect the member variables you mutate, you can scope it to just that if/else block where you make your modifications. You do use _sequence one additional time when generating the return value, but that could use a local copy acquired while the lock is held. So the main thing you are moving outside the lock block is the call to GetTicks().

If you can figure out how to implement this with Interlocked functions, that's going to be the best performance. I'm not an expert, but I don't think you can do it directly, you would probably have to pack your sequence and generation into a single long. A ReaderWriterLockSlim offers more functionality than you need - you have no readers - so it's likely not optimal. You'll want to measure, but out of all the locks I'd guess you'd get the best performance from a SpinLock.

There's a whole use case you mention where these things are allocated per-thread, where presumably you don't want to pay for any thread safety overhead. I would suggest moving the code that requires locking into a separate virtual function with no thread-safety mechanisms, and making a subclass that overrides the implementation in a thread-safe way. This could be as simple as:

protected override long Increment()
{
    lock (_genlock)
    {
         return base.Increment();
    }
}
Source Link
Pierre Menard
  • 2.2k
  • 15
  • 30

Since your lock only needs to protect the member variables you mutate, you can scope it to just that if/else block where you make your modifications. You do use _sequence one additional time when generating the return value, but that could use a local copy acquired while the lock is held. So the main thing you are moving outside the lock block is the call to GetTicks().

If you can figure out how to implement this with Interlocked functions, that's going to be the best performance. A ReaderWriterLockSlim offers more functionality than you need - you have no readers - so it's likely not optimal. You'll want to measure, but out of all the locks I'd guess you'd get the best performance from a SpinLock.

There's a whole use case you mention where these things are allocated per-thread, where presumably you don't want to pay for any thread safety overhead. I would suggest moving the code that requires locking into a separate virtual function with no thread-safety mechanisms, and making a subclass that overrides the implementation in a thread-safe way. This could be as simple as:

protected override long Increment()
{
    lock (_genlock)
    {
         return base.Increment();
    }
}