Refactor exporter - step 4#1085
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1085 +/- ##
==========================================
- Coverage 76.59% 76.17% -0.43%
==========================================
Files 224 225 +1
Lines 6165 6199 +34
==========================================
Hits 4722 4722
- Misses 1443 1477 +34
|
|
|
||
| if (this.SwapIfNull(index, value)) | ||
| { | ||
| this.head = headSnapshot + 1; |
There was a problem hiding this comment.
I know it's a really really big number, but in theory it could wrap around to negative at some point which would throw overflow exception I think? If we switched to ulong head/tail and did unchecked (this.head = headSnapshot + 1) I think the wrap would be fine given the % this.capacity in the algorithm?
There was a problem hiding this comment.
I guess it is impractical to hit that number? Adding the wrapping support requires more than unchecked, it will touch other part of the lock-free algorithm and put additional requirements on memory barriers. So I would prefer to keep it as-is in favor of perf vs. mathematical correctness.
|
|
||
| count = Math.Min(count, this.Count); | ||
|
|
||
| for (int i = 0; i < count; i++) |
There was a problem hiding this comment.
Do you want to provide an additional check with a boolean and an Interlock to prevent 2 threads from accidently entering if the single reader pattern is accidently broken.
|
|
||
| if (this.SwapIfNull(index, value)) | ||
| { | ||
| if (Interlocked.CompareExchange(ref this.head, headSnapshot + 1, headSnapshot) == headSnapshot) |
There was a problem hiding this comment.
Is headSnapshot validation needed, or Interloaded.Add can work here?
There was a problem hiding this comment.
It's is required, otherwise it'll break the 🧙♀️.
There was a problem hiding this comment.
I see, yes, it is required because the item pointed by headSnapshot maybe not in the range of [this.tail, this.head).
|
As the name implied it is a circular buffer, should it |
| throw new ArgumentNullException(nameof(value)); | ||
| } | ||
|
|
||
| while (true) |
There was a problem hiding this comment.
Retry here introduces uncertainty of running time of TryAdd, perhaps return false instead of retry in the while(true) loop, or limit retry count?
There was a problem hiding this comment.
The intention of this function is to return false only when queue is full.
There was a problem hiding this comment.
@ThomsonTan you've actually worried me! 😅 Here goes a PR #1088 to address it.
| private long head = 0; | ||
| private long tail = 0; | ||
|
|
||
| public CircularBuffer(int capacity) |
There was a problem hiding this comment.
Restrict capacity to be power of 2, so the modulo operation % could replaced with a simple bitwise and?
There was a problem hiding this comment.
How much (X%) perf improvement would you expect from modulo?
There was a problem hiding this comment.
div could take tens times of CPU cycles than bitwise arithmetic instruction, but there is also trade off taking more memory (for ceiling(2**size)). This could be a low priority optimization and needs data to prove.
| { | ||
| if (count <= 0) | ||
| { | ||
| yield break; |
There was a problem hiding this comment.
When the queue is empty, wait for notification of new items instead of polling?
There was a problem hiding this comment.
That would make it a normal lock based queue instead of lock-free.
This is a follow up PR of #1078.
Changes
For significant contributions please make sure you have completed the following items: