I not understand. Is you code is working for you? This test return nil on my image:
And what I try to said is as soon as suspend called on waiting process semaphore is not anymore on it suspendingList. 2016-01-08 15:35 GMT+01:00 Henrik Johansen <[hidden email]>:
|
Long standing Case 5959 "Process suspension and Semaphore clash" seems
related... https://pharo.fogbugz.com/default.asp?5959 cheers -ben On Fri, Jan 8, 2016 at 10:45 PM, Denis Kudriashov <[hidden email]> wrote: > I not understand. Is you code is working for you? > > This test return nil on my image: > > sema := Semaphore new. > p:= [ sema waitIfCurtailed: [ r := p suspendingList ] ] fork. > 1 seconds wait. > p terminate2. "your implementation" > r. > > > And what I try to said is as soon as suspend called on waiting process > semaphore is not anymore on it suspendingList. > > > > 2016-01-08 15:35 GMT+01:00 Henrik Johansen <[hidden email]>: >> >> >> On 08 Jan 2016, at 3:24 , Denis Kudriashov <[hidden email]> wrote: >> >> >> 2016-01-08 15:17 GMT+01:00 Henrik Johansen <[hidden email]>: >>> >>> Which is why in terminate I do >>> myList := self suspend. >>> >>> So the semaphore *should* still be the suspendingList, just without the >>> process actually on the list... >> >> >> I just test it in workspace. >> >> sema := Semaphore new. >> p := [sema wait] fork. >> p suspend. >> p suspendingList == nil >> >> sema asArray isEmpty >> >> >> >> Of course, that's something entirely different... >> if you do what I actually do in the modified terminate; >> sema := Semaphore new. >> p := [sema wait ] newProcess. >> p resume. >> 1 second wait. >> list := p suspend. >> "this list is (re)assigned to myList in terminate" >> list == nil >> list == sema >> >> You should get different answers. >> >> Cheers, >> Henry >> >> > |
In reply to this post by Henrik Sperre Johansen
On Fri, Jan 8, 2016 at 9:40 PM, Henrik Johansen
<[hidden email]> wrote: > Here's an alternative implementation, which, instead of checking for the new > method name, hooks into the existing unwind machinery to execute the > waitIfCurtailed: argument. > Which removes the special case from Process >> #terminate, but at the added > cost that in-progress unwinds are executed as if the (suspended) terminating > thread they started executing on, is still the active process. (Which, > arguably, should be done anyways) It feels a bit fragile playing peeking into "Processor activeProcess suspendingList". Also it doesn't work :) It is not sufficient to test with only two processes. You need three, since it is the third process that wakes up incorrectly. lock := Semaphore forMutualExclusion. waitInFirstCritical := Semaphore new. Transcript clear; show: 'excessSignals=' , (lock instVarNamed: 'excessSignals') printString. testBlock := [ :n | Transcript crShow: n printString , ' start'. lock critical2: [ (n=1) ifTrue: [ waitInFirstCritical wait ]. Transcript crShow: n printString, ' done'. ]]. proc1 := (testBlock newProcessWith: {1}) priority: 50. proc2 := (testBlock newProcessWith: {2}) priority: 50. proc3 := (testBlock newProcessWith: {3}) priority: 50. proc1 resume. proc2 resume. proc3 resume. "proc2 terminate." waitInFirstCritical signal. Transcript cr; show: 'excessSignals=' , (lock instVarNamed: 'excessSignals') printString. "proc2 terminate" commented produces the expected result... excessSignals=1 1 start 2 start 3 start 1 done 2 done 3 done excessSignals=1 "proc2 terminate" uncommented produces incorrect ordering... excessSignals=1 1 start 2 start 3 start 3 done "<--should occur after 1" 1 done excessSignals=2 "<--should be 1" Now using "lock := CriticalSection new" provided by Eliot (and removing instVarNamed: 'excessSignals' access from the test script) produces correct result... 1 start 2 start 3 start 1 done 3 done cheers -ben |
I publish version based on new LockOwnership class. It requires slice 17373. Now all test are green 2016-01-10 4:55 GMT+01:00 Ben Coman <[hidden email]>: On Fri, Jan 8, 2016 at 9:40 PM, Henrik Johansen |
On Mon, Jan 11, 2016 at 11:37 PM, Denis Kudriashov <[hidden email]> wrote:
> I publish version based on new LockOwnership class. It requires slice 17373. > Now all test are green Thanks. I look forward to taking a look, but its too late to start tonight. I'll check tomorrow. cheers -ben > > 2016-01-10 4:55 GMT+01:00 Ben Coman <[hidden email]>: >> >> On Fri, Jan 8, 2016 at 9:40 PM, Henrik Johansen >> <[hidden email]> wrote: >> > Here's an alternative implementation, which, instead of checking for the >> > new >> > method name, hooks into the existing unwind machinery to execute the >> > waitIfCurtailed: argument. >> > Which removes the special case from Process >> #terminate, but at the >> > added >> > cost that in-progress unwinds are executed as if the (suspended) >> > terminating >> > thread they started executing on, is still the active process. (Which, >> > arguably, should be done anyways) >> >> It feels a bit fragile playing peeking into "Processor activeProcess >> suspendingList". Also it doesn't work :) It is not sufficient to >> test with only two processes. You need three, since it is the third >> process that wakes up incorrectly. >> >> lock := Semaphore forMutualExclusion. >> waitInFirstCritical := Semaphore new. >> Transcript clear; show: 'excessSignals=' , >> (lock instVarNamed: 'excessSignals') printString. >> testBlock := [ :n | >> Transcript crShow: n printString , ' start'. >> lock critical2: [ >> (n=1) ifTrue: [ waitInFirstCritical wait ]. >> Transcript crShow: n printString, ' done'. >> ]]. >> proc1 := (testBlock newProcessWith: {1}) priority: 50. >> proc2 := (testBlock newProcessWith: {2}) priority: 50. >> proc3 := (testBlock newProcessWith: {3}) priority: 50. >> proc1 resume. >> proc2 resume. >> proc3 resume. >> "proc2 terminate." >> waitInFirstCritical signal. >> Transcript cr; show: 'excessSignals=' , >> (lock instVarNamed: 'excessSignals') printString. >> >> >> "proc2 terminate" commented produces the expected result... >> excessSignals=1 >> 1 start >> 2 start >> 3 start >> 1 done >> 2 done >> 3 done >> excessSignals=1 >> >> "proc2 terminate" uncommented produces incorrect ordering... >> excessSignals=1 >> 1 start >> 2 start >> 3 start >> 3 done "<--should occur after 1" >> 1 done >> excessSignals=2 "<--should be 1" >> >> >> Now using "lock := CriticalSection new" provided by Eliot (and >> removing instVarNamed: 'excessSignals' access from the test script) >> produces correct result... >> 1 start >> 2 start >> 3 start >> 1 done >> 3 done >> >> cheers -ben >> > |
In reply to this post by Denis Kudriashov
Hi Denis, all,
I'm sorry for asking basic questions, but... I thought of this a little and I failed to see the advantage of using ReadWriteLock over monitor / mutex. What's the goal of ReadWriteLock? I mean - when should I use it rather than monitor / mutex? What practical advantage would it have? Best, Jan On Mon, 2016-01-04 at 18:39 +0100, Denis Kudriashov wrote: > Hi. > > I implemented small package ReadWriteLock http://smalltalkhub.com/mc/ > Pharo/ReadWriteLock/main. > > Gofer it > smalltalkhubUser: 'Pharo' project: 'ReadWriteLock'; > configurationOf: 'ReadWriteLock'; > loadStable > > It is reentral read write lock which described in > https://en.wikipedia.org/wiki/Readers–writer_lock. From the article: > > > An ReadWriteLock allows concurrent access for read-only operations, > > while write operations require exclusive access. This means that > > multiple threads can read the data in parallel but an exclusive > > lock is needed for writing or modifying data. When a writer is > > writing the data, all other writers or readers will be blocked > > until the writer is finished writing. > Public API and Key Messages > > - lock := ReadWriteLock new > - lock criticalRead: aBlock > - lock criticalWrite: aBlock > > Implementation based on two semaphores and readers counter. > > Main difficulty is carefully handle process termination during > execution of critical sections. This problem described in > Semaphore>>critical: comment. Same approach is used here. But > synchronisation logic around two semaphores for reading and writing > complicates things very much. No simple way to decompose logic on > multiple methods because information about process interruption > become hidden. > From the Semaphore comment: > > The main trick is assignment right before we go into the wait > > primitive (which is not a real send and therefore not interruptable > > either). So after we can check that waiting is happen or not. > Tests are implemented only for lock scenarios. No tests for described > termination process cases. It is not really clear how to write it. > I will be appreciate if people review code. Maybe you will suggest > simplifications. It is always difficult to implement concurrent > code. > > Best regards, > Denis |
Hi. 12 янв. 2016 г. 11:29 PM пользователь "Jan Vrany" <[hidden email]> написал:
Hi Denis, all, |
In reply to this post by Jan Vrany
These two read together provide a balanced view.
ReaderWriterLock vs Monitor http://www.interact-sw.co.uk/iangblog/2004/04/26/rwlockvsmonitor When to use the ReaderWriterLock https://www.interact-sw.co.uk/iangblog/2004/05/12/rwlock cheers -ben On Wed, Jan 13, 2016 at 6:27 AM, Jan Vrany <[hidden email]> wrote: > Hi Denis, all, > > I'm sorry for asking basic questions, but... > > I thought of this a little and I failed to see the advantage > of using ReadWriteLock over monitor / mutex. What's the goal > of ReadWriteLock? I mean - when should I use it rather than > monitor / mutex? What practical advantage would it have? > > Best, Jan > > > On Mon, 2016-01-04 at 18:39 +0100, Denis Kudriashov wrote: >> Hi. >> >> I implemented small package ReadWriteLock http://smalltalkhub.com/mc/ >> Pharo/ReadWriteLock/main. >> >> Gofer it >> smalltalkhubUser: 'Pharo' project: 'ReadWriteLock'; >> configurationOf: 'ReadWriteLock'; >> loadStable >> >> It is reentral read write lock which described in >> https://en.wikipedia.org/wiki/Readers–writer_lock. From the article: >> >> > An ReadWriteLock allows concurrent access for read-only operations, >> > while write operations require exclusive access. This means that >> > multiple threads can read the data in parallel but an exclusive >> > lock is needed for writing or modifying data. When a writer is >> > writing the data, all other writers or readers will be blocked >> > until the writer is finished writing. >> Public API and Key Messages >> >> - lock := ReadWriteLock new >> - lock criticalRead: aBlock >> - lock criticalWrite: aBlock >> >> Implementation based on two semaphores and readers counter. >> >> Main difficulty is carefully handle process termination during >> execution of critical sections. This problem described in >> Semaphore>>critical: comment. Same approach is used here. But >> synchronisation logic around two semaphores for reading and writing >> complicates things very much. No simple way to decompose logic on >> multiple methods because information about process interruption >> become hidden. >> From the Semaphore comment: >> > The main trick is assignment right before we go into the wait >> > primitive (which is not a real send and therefore not interruptable >> > either). So after we can check that waiting is happen or not. >> Tests are implemented only for lock scenarios. No tests for described >> termination process cases. It is not really clear how to write it. >> I will be appreciate if people review code. Maybe you will suggest >> simplifications. It is always difficult to implement concurrent >> code. >> >> Best regards, >> Denis > |
Denis,
yes, I read it, but I could not find answers there. Ben, thanks! The second article suggests that readers may do blocking operations inside read-critical sections such as IO. If the critical section may block, then I see the advantage. I always thought doing a blocking operation in a critical section is no-no so I haven't considered that case...Thanks! Best, Jan On Wed, 2016-01-13 at 11:31 +0800, Ben Coman wrote: > These two read together provide a balanced view. > > ReaderWriterLock vs Monitor > http://www.interact-sw.co.uk/iangblog/2004/04/26/rwlockvsmonitor > > When to use the ReaderWriterLock > https://www.interact-sw.co.uk/iangblog/2004/05/12/rwlock > > cheers -ben > > On Wed, Jan 13, 2016 at 6:27 AM, Jan Vrany <[hidden email]> > wrote: > > Hi Denis, all, > > > > I'm sorry for asking basic questions, but... > > > > I thought of this a little and I failed to see the advantage > > of using ReadWriteLock over monitor / mutex. What's the goal > > of ReadWriteLock? I mean - when should I use it rather than > > monitor / mutex? What practical advantage would it have? > > > > Best, Jan > > > > > > On Mon, 2016-01-04 at 18:39 +0100, Denis Kudriashov wrote: > > > Hi. > > > > > > I implemented small package ReadWriteLock http://smalltalkhub.com > > > /mc/ > > > Pharo/ReadWriteLock/main. > > > > > > Gofer it > > > smalltalkhubUser: 'Pharo' project: 'ReadWriteLock'; > > > configurationOf: 'ReadWriteLock'; > > > loadStable > > > > > > It is reentral read write lock which described in > > > https://en.wikipedia.org/wiki/Readers–writer_lock. From the artic > > > le: > > > > > > > An ReadWriteLock allows concurrent access for read-only > > > > operations, > > > > while write operations require exclusive access. This means > > > > that > > > > multiple threads can read the data in parallel but an exclusive > > > > lock is needed for writing or modifying data. When a writer is > > > > writing the data, all other writers or readers will be blocked > > > > until the writer is finished writing. > > > Public API and Key Messages > > > > > > - lock := ReadWriteLock new > > > - lock criticalRead: aBlock > > > - lock criticalWrite: aBlock > > > > > > Implementation based on two semaphores and readers counter. > > > > > > Main difficulty is carefully handle process termination during > > > execution of critical sections. This problem described in > > > Semaphore>>critical: comment. Same approach is used here. But > > > synchronisation logic around two semaphores for reading and > > > writing > > > complicates things very much. No simple way to decompose logic on > > > multiple methods because information about process interruption > > > become hidden. > > > From the Semaphore comment: > > > > The main trick is assignment right before we go into the wait > > > > primitive (which is not a real send and therefore not > > > > interruptable > > > > either). So after we can check that waiting is happen or not. > > > Tests are implemented only for lock scenarios. No tests for > > > described > > > termination process cases. It is not really clear how to write > > > it. > > > I will be appreciate if people review code. Maybe you will > > > suggest > > > simplifications. It is always difficult to implement concurrent > > > code. > > > > > > Best regards, > > > Denis > > > > |
In reply to this post by Ben Coman
Thank you Ben for links 2016-01-13 4:31 GMT+01:00 Ben Coman <[hidden email]>: These two read together provide a balanced view. |
thanks! According to the second article, readers may perform blocking operations within read-critical parts like IO.
I can understand the benefit if the crucial area can block. I haven't thought about such situation because I've always believed that halting operations in key sections are bad ideas. Thanks! |
In reply to this post by Denis Kudriashov
The second article asserts that readers may execute blocking activities within read-critical portions, such as IO.
If the important area can be blocked, I can see the benefit. Since I've always thought that stopping activities in crucial areas is a bad idea, I haven't given this problem any attention. |
The second article claims that readers can perform blocking operations within read-critical sections such as IO.
I can understand the advantage if the crucial area can be blocked. I haven't given this matter much thought because I've always believed that suspending efforts in critical sectors is a poor idea. |
In reply to this post by Jan Vrany
But what is the purpose of readLock if anyways we are allowing multiple threads to read. Even if we dont use readlock then also we have multiple threads reading the resource.
Thanks. |
Free forum by Nabble | Edit this page |