Skip to content

Instantly share code, notes, and snippets.

@harrah
Created February 5, 2013 14:09
Show Gist options
  • Save harrah/4714661 to your computer and use it in GitHub Desktop.
Save harrah/4714661 to your computer and use it in GitHub Desktop.
Demonstrates "Resource deadlock avoided" exception on a file lock when there is no deadlock.
import java.io._
object A
{
/*
* Starts two concurrent threads that acquire file locks in a timed manner.
* Arguments:
* initialDelayA(ms) lockTimeA(ms) lockFileA initialDelayB(ms) lockTimeB(ms) lockFileB
*
* Example usage: demonstrates "Resource deadlock avoided" when there is no actual deadlock.
* Run this program concurrently:
* $ scala A 3000 5000 a 1000 7000 b
* $ scala A 1000 7000 a 3000 5000 b
*
* This will throw "IOException: Resource deadlock avoided" because the os doesn't have
* a deadlock detection granularity at the thread level, only at the process level.
*
* Time(s) A1 B1 a2 B2
* 0 start start start start
* 1 lock b lock a
* 2 lock b lock a
* 3 wait on a lock b lock a wait on b
* ...
*
* The os sees process 1 acquire b and wait on a. It sees process 2 acquire a and wait on b.
* It thinks there is deadlock, which would be true if the processes were single threaded.
* There is no deadlock because the locks are in concurrent threads and not nested in a single thread.
* The os doesn't track the file locks at the thread level and doesn't know that, however.
*
* By reducing the lock times to be within the deadlock timeout of the os, the program completes successfully.
**/
def main(args: Array[String]) {
run(args(0).toLong, args(1).toLong, args(2))
run(args(3).toLong, args(4).toLong, args(5))
}
/* Start a new thread that will:
*
* 1. wait `initialDelay` ms
* 2. Acquire a lock on `file`
* 3. wait `lockTime` ms
* 4. Release the lock on `file`.
*/
def run(initialDelay: Long, lockTime: Long, file: String) {
val r = new Runnable {
def run {
println(s"Starting thread for $file")
Thread.sleep(initialDelay)
println(s"Initial wait complete for $file")
val fos = new FileOutputStream(new File(file))
val lock = fos.getChannel.lock
println(s"Locked $file")
try {
Thread.sleep(lockTime)
println(s"Done waiting, $file")
}
finally { lock.release }
println(s"Released lock on $file")
}
}
new Thread(r).start()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment