Hi,
I'm almost done with events. One last question, though: can I fire asynchronous events? It looks like all the events are syncrhonous... Thanks |
Although I actually don't remember having seen this, I guess it could be
done with [self trigger: #someEvent] fork. but perhaps there is a good reason, which I'm missing, for not ever having seen this before ... is there ? Regards. Martin > Hi, > > I'm almost done with events. One last question, though: can I fire > asynchronous events? It looks like all the events are syncrhonous... > > Thanks > |
Martin wrote:
> [self trigger: #someEvent] fork. > > but perhaps there is a good reason, which I'm missing, for not ever having > seen this before ... is there ? I don't think there's any reason not to, it's more a case of it not being something you need all that often. There seem to be two reasons why you might want to do something like that, one is to ensure that a buggy receiver of the trigger can't screw up the operation of the sender. That case could also be handled (synchronously) by: [self trigger: #someEvent] on: Error "or should it be Exception ?" do: [:err | err notifiy]. The other is to ensure that long-running handlers do not slow the sender down, but then if that's the motivation it might be better for the receiver of the notification to do the fork instead. After all it knows when its going to do something slow, but the observee can only guess. One special-case of asynchronous events that I've occasionally wanted is some sort of deferred event where the handler is guaranteed to be invoked in the "Main" (user interface) Process while the trigger can be issued from any Process. I've never got around to trying to implement that, though. It's easy to do if the sender of the event is required to use a special form (equivalent to [self trigger: #someEvent] postToInputQueue), but ideally I'd want it to be the observer that used a special form (#when:deferSending:to: or some-such). -- chris |
Hello Chris
> There seem to be two reasons why you might want to do something like that, one > is to ensure that a buggy receiver of the trigger can't screw up the operation > of the sender. That case could also be handled (synchronously) by: > > [self trigger: #someEvent] > on: Error "or should it be Exception ?" > do: [:err | err notifiy]. Never thought in this, it's good to know it. > One special-case of asynchronous events that I've occasionally wanted is some > sort of deferred event where the handler is guaranteed to be invoked in the > "Main" (user interface) Process while the trigger can be issued from any > Process. I've never got around to trying to implement that, though. It's easy > to do if the sender of the event is required to use a special form (equivalent > to [self trigger: #someEvent] postToInputQueue), but ideally I'd want it to be > the observer that used a special form (#when:deferSending:to: or some-such). Is it possible that this would do the trick ? Perhaps it has perfomance penalties, but still, if all it takes to do such a thing are 3 short methods, then I just can't believe smalltalk (once again). --- Object>>when: anEventSymbol deferSend: aSelector to: anObject self when: anEventSymbol perform: [SessionManager inputState queueDeferredAction: (EventMessageSend receiver: anObject selector: aSelector)] --- I tested it with this script, and seems to work, but then again, I might be missing something, since a few moments ago I didn't even think about doing such a thing ... --- subject := Object new. block := [Transcript nextPutAll: Processor activeProcess id printString; nextPutAll: ' is ui process: '; nextPutAll: Processor isActiveMain printString; cr]. subject when: #event send: #value to: block; when: #event deferSend: #value to: block. [subject trigger: #event] forkAt: 9. 1 to: 10 do: [:i | Transcript nextPutAll: 'hi there'; cr] |
Martin wrote:
> --- > Object>>when: anEventSymbol deferSend: aSelector to: anObject > > self > when: anEventSymbol > perform: > [SessionManager inputState > queueDeferredAction: (EventMessageSend receiver: anObject > selector: aSelector)] > > --- Yes, that should work. Thanks. For some reason I was imagining something a lot more complicated. A different kind of EventMessageSend perhaps... -- chris |
In reply to this post by Chris Uppal-3
Chris Uppal wrote:
> Martin wrote: > > >>[self trigger: #someEvent] fork. >> >>but perhaps there is a good reason, which I'm missing, for not ever having >>seen this before ... is there ? > > > I don't think there's any reason not to, it's more a case of it not being > something you need all that often. [...] > One special-case of asynchronous events that I've occasionally wanted is some > sort of deferred event where the handler is guaranteed to be invoked in the > "Main" (user interface) Process while the trigger can be issued from any > Process. I've never got around to trying to implement that, though. It's easy > to do if the sender of the event is required to use a special form (equivalent > to [self trigger: #someEvent] postToInputQueue), but ideally I'd want it to be > the observer that used a special form (#when:deferSending:to: or some-such). So far I have posted all my asynchronous events into the input queue, just because I didn't want to take too many assumptions on the "process-safety"/"thread-safety" (or whatever the correct term here is) of the receiver. In fact in most of my coding, whenever I have used asynchronous processes, I have tried only to do the bare minimum in those processes (i.e. overlapped blocking system calls) and forward the results to the "main" process for further processing ASAP. I am just wondering, if that is just undue caution on my part - being a Smalltalk beginner - and how lavishly other people use asynchronous processes. What would be the "best practice" when using async processes both in regards to writing your own classes as well as interacting with "foreign" classes? Looking forward to any comments and insights on the matter, Bernhard |
Bernhard,
> So far I have posted all my asynchronous events into the input queue, > just because I didn't want to take too many assumptions on the > "process-safety"/"thread-safety" (or whatever the correct term here is) > of the receiver. FWIW, my experience is that somebody will correct you no matter which term you use :) They are called Process for historical reasons; the reality is that they act more like threads. Either way, you are wise to respect both what can do for you, and to you. > In fact in most of my coding, whenever I have used asynchronous > processes, I have tried only to do the bare minimum in those processes > (i.e. overlapped blocking system calls) and forward the results to the > "main" process for further processing ASAP. > > I am just wondering, if that is just undue caution on my part - being a > Smalltalk beginner When in doubt about the receiver, it's reasonable. However, you are denying yourself considerable flexibility if you run everything on the main thread. Any GUI updates should be synchronized with the main thread (posted to the message queue via #post* or #queueDeferredAction:), but you can frequently do a lot of computation on a background thread first, and then do only the work required for the actual update on the main thread. If multiple threads access an object, then either it or you must arrange for proper synchronization; SharedQueue, SharedLookupTable, most if not all weak collections are thread safe. For other classes, you need to help them. See Mutex>>critical:. Note that some problems might require multiple mutexes. You might use either a shared collection or a mutex-protected collection to hold "connections" (to just about anything) and then give each connection its own mutex (or two??) to synchronize reads and writes over the individual connection. A search of the archives will turn up some of my past mumblings on the subject, including mention of tools useful for hunting down deadlocks. Note that you will typically want to overprotect, as a deadlock is far easier to detect than random results due to inadequate synchronization. The Process Safe Class pattern from Dolphin's early days is still well worth reading. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Bill Schwab wrote:
> Bernhard, [...] > FWIW, my experience is that somebody will correct you no matter which > term you use :) They are called Process for historical reasons; the > reality is that they act more like threads. Either way, you are wise to > respect both what can do for you, and to you. Very true, as I've had _some_ expeciences (in other programming languages) of what asynchronous thread can do to me ;) That gives me a healthy dose of respect for them. [...] > When in doubt about the receiver, it's reasonable. However, you are > denying yourself considerable flexibility if you run everything on the > main thread. > > Any GUI updates should be synchronized with the main thread (posted to > the message queue via #post* or #queueDeferredAction:), but you can > frequently do a lot of computation on a background thread first, and > then do only the work required for the actual update on the main thread. So what about triggering of events? Should the sender only do them in the main thread or should the receiver-method post a send to itself into the message queue, if the current thread isn't already the main one? > If multiple threads access an object, then either it or you must arrange > for proper synchronization; SharedQueue, SharedLookupTable, most if not > all weak collections are thread safe. > > For other classes, you need to help them. See Mutex>>critical:. Note > that some problems might require multiple mutexes. You might use either > a shared collection or a mutex-protected collection to hold > "connections" (to just about anything) and then give each connection its > own mutex (or two??) to synchronize reads and writes over the individual > connection. A search of the archives will turn up some of my past > mumblings on the subject, including mention of tools useful for hunting > down deadlocks. > > Note that you will typically want to overprotect, as a deadlock is far > easier to detect than random results due to inadequate synchronization. > > The Process Safe Class pattern from Dolphin's early days is still well > worth reading. Thank you, Bill, for the reading pointers. I'll read up on it. Bernhard |
Bernhard,
> So what about triggering of events? Should the sender only do them in > the main thread or should the receiver-method post a send to itself into > the message queue, if the current thread isn't already the main one? I will defer to OA on this, but the event mechanism itself appears to be sufficiently thread safe to not blow up over various threads registering and unregistering interest in events, but the event sinks are in general not going to be thread safe. When in doubt, you can do something like [ self trigger:#notThreadSafe: with:resultsOfSomeUglyCalculation. ] post or otherwise queue the triggering so it happens on the GUI thread. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
Bill,
>> So what about triggering of events? Should the sender only do them in >> the main thread or should the receiver-method post a send to itself >> into the message queue, if the current thread isn't already the main one? > > > I will defer to OA on this, but the event mechanism itself appears to be > sufficiently thread safe to not blow up over various threads registering > and unregistering interest in events, but the event sinks are in general > not going to be thread safe. So if the event sinks are not thread-safe, then the triggering object should only do it in the main thread, correct? > When in doubt, you can do something like > > [ self trigger:#notThreadSafe: with:resultsOfSomeUglyCalculation. ] post > > or otherwise queue the triggering so it happens on the GUI thread. So adding a method like: BlockClosure>>evaluateInMainProcess Processor isActiveMain ifTrue: [ self value ] ifFalse: [ self postToInputQueue ] and then doing something like: [ self trigger: #notThreadSafe: with: resultsOfSomeUglyCalculation ] evaluateInMainProcess should be sufficiently convenient in addition to being safe. Bernhard |
Free forum by Nabble | Edit this page |