3 replaced http://stackoverflow.com/ with https://stackoverflow.com/
source | link

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this questionthis question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, A is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need A any more, and you destroy it some way or another. But you're being called from A - if A, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states, and extra code and bugs from handling these; better for A to just stop working entirely after you don't need it anymore other than continue in some intermediate state.

In my pattern, A would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since A just returns. Now, if the callback doesn't destroy A, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy A, A's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, A is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need A any more, and you destroy it some way or another. But you're being called from A - if A, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states, and extra code and bugs from handling these; better for A to just stop working entirely after you don't need it anymore other than continue in some intermediate state.

In my pattern, A would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since A just returns. Now, if the callback doesn't destroy A, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy A, A's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, A is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need A any more, and you destroy it some way or another. But you're being called from A - if A, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states, and extra code and bugs from handling these; better for A to just stop working entirely after you don't need it anymore other than continue in some intermediate state.

In my pattern, A would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since A just returns. Now, if the callback doesn't destroy A, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy A, A's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

2 edited body
source | link

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, BA is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need BA any more, and you destroy it some way or another. But you're being called from BA - if BA, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states, and new problems;extra code and bugs from handling these; better for BA to just stop working entirely after you don't need it anymore other than continue thinking all is finein some intermediate state.

In my pattern, BA would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since BA just returns. Now, if the callback doesn't destroy BA, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy BA, B'sA's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, B is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need B any more, and you destroy it some way or another. But you're being called from B - if B, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states and new problems; better for B to just stop working entirely after you don't need it anymore other than continue thinking all is fine.

In my pattern, B would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since B just returns. Now, if the callback doesn't destroy B, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy B, B's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, A is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need A any more, and you destroy it some way or another. But you're being called from A - if A, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states, and extra code and bugs from handling these; better for A to just stop working entirely after you don't need it anymore other than continue in some intermediate state.

In my pattern, A would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since A just returns. Now, if the callback doesn't destroy A, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy A, A's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.

1
source | link

I've found that processing events using a stack of internal events (more specifically, a LIFO queue with arbitrary removal) greatly simplifies event-driven programming. It allows you to split the processing of an "external event" into several smaller "internal events", with well-defined state in between. For more information, see my answer to this question.

Here I present a simple example which is solved by this pattern.

Suppose you are using object A to perform some service, and you give it a callback to inform you when it's done. However, B is such that after calling your callback, it may need to do some more work. A hazard arises when, within that callback, you decide that you don't need B any more, and you destroy it some way or another. But you're being called from B - if B, after your callback returns, cannot safely figure out that it was destroyed, a crash could result when it attempts to perform the remaining work.

NOTE: It's true that you could do the "destruction" in some other way, like decrementing a refcount, but that just leads to intermediate states and new problems; better for B to just stop working entirely after you don't need it anymore other than continue thinking all is fine.

In my pattern, B would simply schedule the further work it needs to do by pushing an internal event (job) into the event loop's LIFO queue, then proceed to call the callback, and return to event loop immediately. This piece of code it no longer a hazard, since B just returns. Now, if the callback doesn't destroy B, the pushed job will eventually be executed by the event loop to do its extra work (after the callback is done, and all its pushed jobs, recursively). On the other hand, if the callback does destroy B, B's destructor or deinit function can remove the pushed job from the event stack, implicitly preventing execution of the pushed job.