Skip to content

Commit b2bbaf1

Browse files
committed
rewrite requestImage() to fix errors/slowness/concurrency problems
1 parent 43bc1af commit b2bbaf1

2 files changed

Lines changed: 25 additions & 80 deletions

File tree

core/src/processing/core/PApplet.java

Lines changed: 24 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@
6262
import java.text.*;
6363
import java.util.*;
6464
import java.util.concurrent.BlockingQueue;
65+
import java.util.concurrent.ExecutorService;
66+
import java.util.concurrent.Executors;
6567
import java.util.concurrent.LinkedBlockingQueue;
68+
import java.util.concurrent.ThreadFactory;
69+
import java.util.concurrent.atomic.AtomicInteger;
6670
import java.util.regex.*;
6771
import java.util.zip.*;
6872

@@ -5431,9 +5435,10 @@ public PImage loadImage(String filename) {
54315435
*/
54325436
public PImage loadImage(String filename, String extension) { //, Object params) {
54335437

5434-
// await... has to run on the main thread, because P2D and P3D call GL functions
5435-
// If this runs on background, requestImage() already called await... on the main thread
5436-
if (g != null && !Thread.currentThread().getName().startsWith(ASYNC_IMAGE_LOADER_THREAD_PREFIX)) {
5438+
// awaitAsyncSaveCompletion() has to run on the main thread, because P2D
5439+
// and P3D call GL functions. If this runs on background, requestImage()
5440+
// already called awaitAsyncSaveCompletion() on the main thread.
5441+
if (g != null && !Thread.currentThread().getName().startsWith(REQUEST_IMAGE_THREAD_PREFIX)) {
54375442
g.awaitAsyncSaveCompletion(filename);
54385443
}
54395444

@@ -5561,8 +5566,12 @@ public PImage loadImage(String filename, String extension) { //, Object params)
55615566
}
55625567

55635568

5569+
static private final String REQUEST_IMAGE_THREAD_PREFIX = "requestImage";
5570+
// fixed-size thread pool used by requestImage()
5571+
ExecutorService requestImagePool;
5572+
5573+
55645574
public PImage requestImage(String filename) {
5565-
// return requestImage(filename, null, null);
55665575
return requestImage(filename, null);
55675576
}
55685577

@@ -5596,62 +5605,17 @@ public PImage requestImage(String filename, String extension) {
55965605
g.awaitAsyncSaveCompletion(filename);
55975606
}
55985607
PImage vessel = createImage(0, 0, ARGB);
5599-
AsyncImageLoader ail =
5600-
new AsyncImageLoader(filename, extension, vessel);
5601-
ail.start();
5602-
return vessel;
5603-
}
5604-
5605-
5606-
// /**
5607-
// * @nowebref
5608-
// */
5609-
// public PImage requestImage(String filename, String extension, Object params) {
5610-
// PImage vessel = createImage(0, 0, ARGB, params);
5611-
// AsyncImageLoader ail =
5612-
// new AsyncImageLoader(filename, extension, vessel);
5613-
// ail.start();
5614-
// return vessel;
5615-
// }
5616-
5617-
5618-
/**
5619-
* By trial and error, four image loading threads seem to work best when
5620-
* loading images from online. This is consistent with the number of open
5621-
* connections that web browsers will maintain. The variable is made public
5622-
* (however no accessor has been added since it's esoteric) if you really
5623-
* want to have control over the value used. For instance, when loading local
5624-
* files, it might be better to only have a single thread (or two) loading
5625-
* images so that you're disk isn't simply jumping around.
5626-
*/
5627-
public int requestImageMax = 4;
5628-
volatile int requestImageCount;
56295608

5630-
private static final String ASYNC_IMAGE_LOADER_THREAD_PREFIX = "ASYNC_IMAGE_LOADER";
5631-
5632-
class AsyncImageLoader extends Thread {
5633-
String filename;
5634-
String extension;
5635-
PImage vessel;
5636-
5637-
public AsyncImageLoader(String filename, String extension, PImage vessel) {
5638-
// Give these threads distinct name so we can check whether we are loading
5639-
// on the main/background thread; for now they are all named the same
5640-
super(ASYNC_IMAGE_LOADER_THREAD_PREFIX);
5641-
this.filename = filename;
5642-
this.extension = extension;
5643-
this.vessel = vessel;
5609+
// if the image loading thread pool hasn't been created, create it
5610+
if (requestImagePool == null) {
5611+
ThreadFactory factory = new ThreadFactory() {
5612+
public Thread newThread(Runnable r) {
5613+
return new Thread(r, REQUEST_IMAGE_THREAD_PREFIX);
5614+
}
5615+
};
5616+
requestImagePool = Executors.newFixedThreadPool(4, factory);
56445617
}
5645-
5646-
@Override
5647-
public void run() {
5648-
while (requestImageCount == requestImageMax) {
5649-
try {
5650-
Thread.sleep(10);
5651-
} catch (InterruptedException e) { }
5652-
}
5653-
requestImageCount++;
5654-
5618+
requestImagePool.execute(() -> {
56555619
PImage actual = loadImage(filename, extension);
56565620

56575621
// An error message should have already printed
@@ -5669,31 +5633,11 @@ public void run() {
56695633
vessel.pixelHeight = actual.height;
56705634
vessel.pixelDensity = 1;
56715635
}
5672-
requestImageCount--;
5673-
}
5636+
});
5637+
return vessel;
56745638
}
56755639

56765640

5677-
// done internally by ImageIcon
5678-
// /**
5679-
// * Load an AWT image synchronously by setting up a MediaTracker for
5680-
// * a single image, and blocking until it has loaded.
5681-
// */
5682-
// protected PImage loadImageMT(Image awtImage) {
5683-
// MediaTracker tracker = new MediaTracker(this);
5684-
// tracker.addImage(awtImage, 0);
5685-
// try {
5686-
// tracker.waitForAll();
5687-
// } catch (InterruptedException e) {
5688-
// //e.printStackTrace(); // non-fatal, right?
5689-
// }
5690-
//
5691-
// PImage image = new PImage(awtImage);
5692-
// image.parent = this;
5693-
// return image;
5694-
// }
5695-
5696-
56975641
/**
56985642
* Use Java 1.4 ImageIO methods to load an image.
56995643
*/

core/todo.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
0265 (3.4)
22
X change lack of blendMode() to a warning rather than an error in PDF
33
X rewrite exec() to do threads, also handle fast/excessive output cases
4+
X rewrite requestImage() to fix errors/slowness/concurrency problems
45

56
data classes
67
X add Double and Long versions of the data classes

0 commit comments

Comments
 (0)