@@ -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