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