Henrik Bengtsson
2013-Apr-05 19:23 UTC
[Rd] parallel: Race-condition concern regarding graphics devices in a multi-thread environment
Hi, I'm trying to figure out how to safely make sure that I close the same graphics device that I opened earlier in a thread (and not one opened by a parallel thread). In a *single-thread* environment, one can do the following to open and close a device: makePlot <- function(i) { filename <- sprintf("foo%d.png", i); png(filename); idx <- dev.cur(); on.exit(dev.off(idx)); plot(1:10, col=i); title(main=i); filename; } # makePlot() However, in a *multi-thread* environment, e.g. res <- mclapply(1:4, FUN=makePlot, mc.cores=4); the following race-condition problem may occur, because of the non-atomicity(?) of (i) png() and (ii) dev.cur(): 1. Thread #1: png("foo1.png") 2. Thread #2: png("foo2.png") 3. Thread #1: idx <- dev.cur(); # idx == 3 4. Thread #2: idx <- dev.cur(); # idx == 3 (same device!) ... 5. Thread #1: dev.off(idx); # Closes device #3 6. Thread #2: plot(1:10, col=2); # Trying to plot, which opens a new on-screen device (or to another active device) since device #3 is closed. 7. Thread #2: dev.off(idx) # Trying to close device #3, which is already closed. On this topic, there are some clues/notes on concern in the vignette of the 'parallel' package, but not enough to answer my concerns/solve my problems. Any other references/discussion on this (other that source code)? Q1. Is there already a built-in protection against the above race condition? Q2. If not on Q1, is there a way/strategy to get hold of the device (index) for the graphics devices that was opened by png() without using dev.cur()? If not on Q2, what about transitioning to have graphics device functions return the opened device (index) (cf. connections), e.g. idx <- png(...). A quick look at ?png and ?x11 show that those functions does not return anything (although code inspections show that they may return something, but always NULL when I try). Comments? Henrik
Simon Urbanek
2013-Apr-05 21:44 UTC
[Rd] parallel: Race-condition concern regarding graphics devices in a multi-thread environment
Henrik, there are no threads. Hence you're on the wrong track there, it has nothing to do with device numbers/devices.The device number will be the same in all processes and that's ok. The issue here really is which png() pack-end are you using? (You didn't say). Some back-ends (like X11) cannot be run in forked environment, so you can't use them. I don't use png() myself, but I do know that CairoPNG() from the Cairo package works when forked. Cheers, Simon On Apr 5, 2013, at 12:23 PM, Henrik Bengtsson <hb at biostat.ucsf.edu> wrote:> Hi, > > I'm trying to figure out how to safely make sure that I close the same > graphics device that I opened earlier in a thread (and not one opened > by a parallel thread). In a *single-thread* environment, one can do > the following to open and close a device: > > makePlot <- function(i) { > filename <- sprintf("foo%d.png", i); > png(filename); > idx <- dev.cur(); > on.exit(dev.off(idx)); > plot(1:10, col=i); > title(main=i); > filename; > } # makePlot() > > However, in a *multi-thread* environment, e.g. > > res <- mclapply(1:4, FUN=makePlot, mc.cores=4); > > the following race-condition problem may occur, because of the > non-atomicity(?) of (i) png() and (ii) dev.cur(): > > 1. Thread #1: png("foo1.png") > 2. Thread #2: png("foo2.png") > 3. Thread #1: idx <- dev.cur(); # idx == 3 > 4. Thread #2: idx <- dev.cur(); # idx == 3 (same device!) > ... > 5. Thread #1: dev.off(idx); # Closes device #3 > 6. Thread #2: plot(1:10, col=2); # Trying to plot, which opens a new > on-screen device (or to another active device) since device #3 is > closed. > 7. Thread #2: dev.off(idx) # Trying to close device #3, which is already closed. > > On this topic, there are some clues/notes on concern in the vignette > of the 'parallel' package, but not enough to answer my concerns/solve > my problems. Any other references/discussion on this (other that > source code)? > > > Q1. Is there already a built-in protection against the above race condition? > > Q2. If not on Q1, is there a way/strategy to get hold of the device > (index) for the graphics devices that was opened by png() without > using dev.cur()? > > If not on Q2, what about transitioning to have graphics device > functions return the opened device (index) (cf. connections), e.g. idx > <- png(...). A quick look at ?png and ?x11 show that those functions > does not return anything (although code inspections show that they may > return something, but always NULL when I try). > > > Comments? > > Henrik > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > >
Maybe Matching Threads
- R-level expansion of Rplot%03d.png
- determining plot location in lattice
- filterMicroRna function: Sample replicates in preprocessing Agilent miRNA dataset
- setting par(srt) according to plot aspect ratio
- Race condition on parallel package's mcexit and rmChild