Hi Andreas,
Why using a primitive ? Because you are sure that processes are mutually excluded ?
In this case, why not using a GlobalMutex to get similar protection
Of course MutexSet cannot work due to deadlock... but this LockSet might:
Object subclass: #LockSet instanceVariableNames: 'array' classVariableNames: 'GlobalMutex' poolDictionaries: '' category: 'Kernel-Processes'
LockSet>>initialize array := Array new
LockSet>>withAll: locks array := locks
LockSet>>mutex "a global mutex with lazy initialization" GlobalMutex ifNil: [GlobalMutex := Mutex new]. GlobalMutex
LockSet>>critical: aBlock "evaluate aBlock if we can acquire all locks" | indexFailed | [indexFailed := self mutex critical: [(1 to: array size) detect: [:i | (array at: iLock) acquireNoWait = false] ifNone: [aBlock value. 1 to: array size do: [:i | (array at: i) signal]. 0]]]. indexFailed = 0] whileFalse: [(1 to: indexFailed -1) do: [:i | (array at: i) signal]. (array at: indexFailed) wait; signal].
Semaphore>>acquireNoWait | waitingProcess wakeupProcess ok | waitingProcess := Processor activeProcess. ok := true. wakeupProcess := [Processor yield. ok := false. self resumeProcess: waitingProcess] fork. self wait. wakeupProcess terminate. ^ok
You can replace wait by acquireLock, signal by releaseLock and acquireNoWait by acquireLockNoWait and replace Semaphore with your own Lock class...
I did not try it cause it's late but maybe you will.
Nicolas
Le Mardi 27 Juin 2006 00:12, Andreas Raab a écrit :
Hi Folks -
I have an interesting little problem that can be trivially solved with help from the VM but that I'm curious if there is a way of doing it from Squeak directly. Here is the problem:
Given a set of N locks (semaphores), how can multiple processes acquire subsets of those locks without deadlocking? E.g., it's fairly obvious that if one process attempts to acquire lock A and B and another one lock B and A that this leads to deadlock in a hurry. What's in particular problematic for my use case is that I don't know which semaphores are part of said set of locks and that I can't establish a total order to make sure that lock A always gets acquired before lock B.
What I've been contemplating is to add a primitive which does the following: It attempts to acquire all the locks given as argument and if one of them cannot be acquired it immediately releases all the locks acquired so far and leaves the process suspended on the "failing" lock. The return value will indicate whether all the locks were acquired and therefore one can write a loop like here to acquire all of the locks:
[self primitiveAcquireAll: locks] whileFalse.
In other words, if all the locks can be acquired the code just marches through. If it fails to acquire a lock the process will stay suspended until that particular lock is released and then retry to acquire the locks.
Is it possible to do that without a VM change?
Cheers,
- Andreas