private void sleep() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }
/** * @return if <0, then this pipe should be stopped. If ==0, it should not wait. If >0, if it * should wait */ int execute() { if (!lock.tryAcquire()) return 1; // currently being accessed Thread myThread = Thread.currentThread(); int threadIndex = -1; for (int i = 0; i < threads.length; i++) { if (threads[i] == null) { threads[i] = myThread; threadIndex = i; break; } if (myThread != threads[i]) continue; threadIndex = i; break; } Signal signal; if (threadIndex < 0) { signal = dummySignal; } else { SignalImpl s = signals[threadIndex]; s.threadIndex = threadIndex; s.signaled = false; signal = s; } boolean hasData; try { hasData = poll(signal, null); } finally { signal.signal(); if (threadIndex < 0) lock.release(); } return 0; }
@Override public void run() { try { while (started) { int result = execute(); if (result < 0) break; if (result > 0) { if (sleep > 0) { Thread.sleep(sleep); sleptTime += sleep; } else if (sleep < 0) Thread.yield(); } else if (adding) { Thread.sleep(1); } else { if (sleep > 0) { incrementTime++; if (incrementTime % 1_000_000 == 0) { toSleepTime += sleep; if (sleptTime < toSleepTime) { sleptTime += sleep; Thread.sleep(sleep); } } } } } } catch (InterruptedException e) { if (started) { if (listener == null) logger.warn("polling", e); else listener.exceptionThrown(e); } } catch (Exception e) { if (listener == null) logger.error("polling", e); else listener.exceptionThrown(e); } }
@Override public synchronized Receptor<T> takeReceptor() { if (!freeReceptors.isEmpty()) { ReceptorImpl impl = (ReceptorImpl) freeReceptors.remove(0); impl.skips = 0; return impl; } int length = inputs.length() + 1; final AtomicReferenceArray<T> inputs = new AtomicReferenceArray<>(length); this.inputs = inputs; final List<ReceptorImpl> newReuseReceptors = new ArrayList<>(length); for (int i = 0; i < length; i++) { newReuseReceptors.add(new ReceptorImpl(i)); } executor.execute( () -> { long lastTime = System.currentTimeMillis(); try { boolean empty = false; while (!empty && started) { empty = true; for (int i = 0; i < outputs.length(); i++) { T result = outputs.get(i); if (result == null) continue; Thread.sleep(1); empty = false; if (lastTime + 30_000 < System.currentTimeMillis()) { lastTime = System.currentTimeMillis(); logger.error( "unable to set receptors for " + producer + " i=" + i + " result=" + result); if (pool != null) logger.warn("pool=" + pool.producer); } break; } } } catch (InterruptedException e) { logger.warn("takeReceptor", e); } finally { reuseReceptors = newReuseReceptors; outputs = inputs; } }); return new ReceptorImpl(length - 1); }
/** * Look for data from all the inputs * * @return true if data was consumed */ private boolean poll(Signal signal, Signal parent) { AtomicReferenceArray<T> o = outputs; for (int i = 0; i < o.length(); i++) { T input = o.getAndSet(i, null); if (input == null) continue; long seq = ++sequence; if (parent != null) parent.signal(); S product = producer.execute(input, reuseReceptors.get(i), signal); signal.signal(); if (!consume(product, seq, 0)) { Thread.yield(); if (!consume(product, seq, 0)) logger.info( "failed to consume product (" + product + ") from producer (" + producer + ")"); } producer.complete(product); return product != null; } return false; }
public void start() { inputs = new AtomicReferenceArray<>(0); outputs = inputs; freeReceptors = new CopyOnWriteArrayList<>(); sequence = 0; finalSequence = 0; finalProduct = null; reuseReceptors = new ArrayList<>(0); executor = Executors.newSingleThreadExecutor(); started = true; if (poolSize > 0) { group = new ThreadGroup("FatPipe"); group.setMaxPriority(Thread.MAX_PRIORITY); } signals = new SignalImpl[ARBITARY_THREADS + poolSize]; threads = new Thread[ARBITARY_THREADS + poolSize]; startTime = System.currentTimeMillis(); sleptTime = 0; toSleepTime = 0; for (int i = 0; i < poolSize; i++) { Thread t = new Thread(group, this, name + "-" + i); t.setDaemon(true); threads[i] = t; t.start(); if (sleep == 0) t.setPriority(Thread.MAX_PRIORITY); else if (sleep < 0) t.setPriority(Thread.NORM_PRIORITY); else t.setPriority(Thread.MIN_PRIORITY); } for (int i = 0; i < signals.length; i++) { signals[i] = new SignalImpl(lock); } if (pool != null) pool.add(this); lock.release(); }
/** * @param product * @param sequence * @return false if there is an error */ boolean consume(S product, long sequence, long sleep) { if (product == null) return true; // make copies Consumer<S>[] consumers = this.consumers; AtomicLongArray outUse = this.outUse; long[] consumerSeqs = this.consumerSeqs; if (outUse.length() != consumers.length) return false; for (int j = 0; j < consumers.length; j++) { if (!consumers[j].isConsuming()) continue; long time = System.nanoTime(); if (!outUse.compareAndSet(j, 0, time)) continue; try { if (sequence <= consumerSeqs[j]) { outUse.lazySet(j, 0); if (outUse != this.outUse) resetConsumer(consumers[j]); break; } consumerSeqs[j] = sequence; consumers[j].consume(product, time); if (sleep > 0) Thread.sleep(sleep); outUse.lazySet(j, 0); if (outUse != this.outUse) { resetConsumer(consumers[j]); break; } } catch (Exception e) { if (listener == null) logger.error("consume", e); else listener.exceptionThrown(e); } } finishConsuming(product, sequence); return true; }