@@ -44,20 +44,20 namespace Implab.Parallels { | |||
|
44 | 44 | // this is the last element, |
|
45 | 45 | // then try to update the tail |
|
46 | 46 | if (first != Interlocked.CompareExchange(ref m_last, null, first)) { |
|
47 |
// this is |
|
|
47 | // this is the race condition | |
|
48 | 48 | if (m_last == null) |
|
49 | 49 | // the queue is empty |
|
50 | 50 | return false; |
|
51 |
// tail has been changed, |
|
|
51 | // tail has been changed, we need to restart | |
|
52 | 52 | continue; |
|
53 | 53 | } |
|
54 | 54 | |
|
55 | 55 | // tail succesfully updated and first.next will never be changed |
|
56 |
// other readers will fail due to inconsistency m_last != m_fist |
|
|
57 |
// |
|
|
56 | // other readers will fail due to inconsistency m_last != m_fist && m_first.next == null | |
|
57 | // however the parallel writer may update the m_first since the m_last is null | |
|
58 | 58 | |
|
59 |
// so we need to fix inconsistency by setting m_first to null |
|
|
60 |
// updated by |
|
|
59 | // so we need to fix inconsistency by setting m_first to null or if it has been | |
|
60 | // updated by the writer already then we should just to give up | |
|
61 | 61 | Interlocked.CompareExchange(ref m_first, null, first); |
|
62 | 62 | break; |
|
63 | 63 |
@@ -80,11 +80,11 namespace Implab { | |||
|
80 | 80 | } |
|
81 | 81 | } |
|
82 | 82 | |
|
83 |
const int U |
|
|
84 |
const int T |
|
|
85 |
const int S |
|
|
86 |
const int R |
|
|
87 |
const int C |
|
|
83 | const int UNRESOLVED_SATE = 0; | |
|
84 | const int TRANSITIONAL_STATE = 1; | |
|
85 | const int SUCCEEDED_STATE = 2; | |
|
86 | const int REJECTED_STATE = 3; | |
|
87 | const int CANCELLED_STATE = 4; | |
|
88 | 88 | |
|
89 | 89 | readonly bool m_cancellable; |
|
90 | 90 | |
@@ -113,16 +113,16 namespace Implab { | |||
|
113 | 113 | } |
|
114 | 114 | |
|
115 | 115 | bool BeginTransit() { |
|
116 |
return U |
|
|
116 | return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE); | |
|
117 | 117 | } |
|
118 | 118 | |
|
119 | 119 | void CompleteTransit(int state) { |
|
120 |
if (T |
|
|
120 | if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE)) | |
|
121 | 121 | throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state"); |
|
122 | 122 | } |
|
123 | 123 | |
|
124 | 124 | void WaitTransition() { |
|
125 |
while (m_state == T |
|
|
125 | while (m_state == TRANSITIONAL_STATE) { | |
|
126 | 126 | /* noop */ |
|
127 | 127 | } |
|
128 | 128 | } |
@@ -135,7 +135,7 namespace Implab { | |||
|
135 | 135 | |
|
136 | 136 | public bool IsCancelled { |
|
137 | 137 | get { |
|
138 |
return m_state == C |
|
|
138 | return m_state == CANCELLED_STATE; | |
|
139 | 139 | } |
|
140 | 140 | } |
|
141 | 141 | |
@@ -151,11 +151,11 namespace Implab { | |||
|
151 | 151 | public void Resolve(T result) { |
|
152 | 152 | if (BeginTransit()) { |
|
153 | 153 | m_result = result; |
|
154 |
CompleteTransit(S |
|
|
154 | CompleteTransit(SUCCEEDED_STATE); | |
|
155 | 155 | OnStateChanged(); |
|
156 | 156 | } else { |
|
157 | 157 | WaitTransition(); |
|
158 |
if (m_state != C |
|
|
158 | if (m_state != CANCELLED_STATE) | |
|
159 | 159 | throw new InvalidOperationException("The promise is already resolved"); |
|
160 | 160 | } |
|
161 | 161 | } |
@@ -183,11 +183,11 namespace Implab { | |||
|
183 | 183 | public void Reject(Exception error) { |
|
184 | 184 | if (BeginTransit()) { |
|
185 | 185 | m_error = error; |
|
186 |
CompleteTransit(R |
|
|
186 | CompleteTransit(REJECTED_STATE); | |
|
187 | 187 | OnStateChanged(); |
|
188 | 188 | } else { |
|
189 | 189 | WaitTransition(); |
|
190 |
if (m_state == S |
|
|
190 | if (m_state == SUCCEEDED_STATE) | |
|
191 | 191 | throw new InvalidOperationException("The promise is already resolved"); |
|
192 | 192 | } |
|
193 | 193 | } |
@@ -198,7 +198,7 namespace Implab { | |||
|
198 | 198 | /// <returns><c>true</c> Операция была отменена, обработчики не будут вызваны.<c>false</c> отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.</returns> |
|
199 | 199 | public bool Cancel() { |
|
200 | 200 | if (BeginTransit()) { |
|
201 |
CompleteTransit(C |
|
|
201 | CompleteTransit(CANCELLED_STATE); | |
|
202 | 202 | OnStateChanged(); |
|
203 | 203 | return true; |
|
204 | 204 | } else { |
@@ -545,11 +545,11 namespace Implab { | |||
|
545 | 545 | throw new TimeoutException(); |
|
546 | 546 | |
|
547 | 547 | switch (m_state) { |
|
548 |
case S |
|
|
548 | case SUCCEEDED_STATE: | |
|
549 | 549 | return m_result; |
|
550 |
case C |
|
|
550 | case CANCELLED_STATE: | |
|
551 | 551 | throw new OperationCanceledException(); |
|
552 |
case R |
|
|
552 | case REJECTED_STATE: | |
|
553 | 553 | throw new TargetInvocationException(m_error); |
|
554 | 554 | default: |
|
555 | 555 | throw new ApplicationException(String.Format("Invalid promise state {0}", m_state)); |
@@ -592,13 +592,13 namespace Implab { | |||
|
592 | 592 | |
|
593 | 593 | protected virtual void InvokeHandler(HandlerDescriptor handler) { |
|
594 | 594 | switch (m_state) { |
|
595 |
case S |
|
|
595 | case SUCCEEDED_STATE: | |
|
596 | 596 | handler.Resolve(m_result); |
|
597 | 597 | break; |
|
598 |
case R |
|
|
598 | case REJECTED_STATE: | |
|
599 | 599 | handler.Reject(m_error); |
|
600 | 600 | break; |
|
601 |
case C |
|
|
601 | case CANCELLED_STATE: | |
|
602 | 602 | handler.Cancel(); |
|
603 | 603 | break; |
|
604 | 604 | default: |
General Comments 0
You need to be logged in to leave comments.
Login now