CompilerParallelWorker.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Компилятор языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package ru.malik.elaborarer.avtoo.compiler;

import avt.io.*;
import avt.lang.array.*;
import avt.util.*;
import ru.malik.elaborarer.avtoo.lang.*;

public class CompilerParallelWorker(Object)
{
    private int fldIndex;
    private int fldTerminates;
    private Exception fldException;
    private ObjectArray fldTargets;
    private final int fldMaxThreads;
    private final Thread fldContext;
    private final Object fldMonitor;
    private final Hashtable fldObjects;
    
    public (int maxThreads) {
        fldMaxThreads = maxThreads < 1 ? 1 : maxThreads;
        fldContext = Thread.current();
        fldMonitor = new Object();
        fldObjects = new Hashtable();
    }

    public void run(CompilerRunnable handler) throws IOException, CompilerException {
        if(fldContext != Thread.current())
        {
            throw new IllegalParallelWorkerState(package.getResourceString("parallelworker.run"));
        }
        int maxThreads = fldMaxThreads;
        int count = Platform.instance.processorNumberOfCores;
        Runnable runnable = new CompilerParallelWorkerRunnable(this, handler);
        if((count = (count >> 1) + (count & 1)) > maxThreads) count = maxThreads;
        fldIndex = 0;
        fldException = null;
        fldTerminates = count;
        Hashtable objects = fldObjects;
        objects.clear();
        if(!(handler instanceof CompilerThreadObjectCreator))
        {
            while(count-- > 0)
            {
                (new Thread(runnable)).start();
            }
        } else
        {
            for(CompilerThreadObjectCreator creator = (CompilerThreadObjectCreator) handler; count-- > 0; )
            {
                Thread thread = new Thread(runnable);
                objects[thread] = creator.createThreadObject();
                thread.start();
            }
        }
        synchronized with(fldMonitor)
        {
            do
            {
                try
                {
                    wait();
                }
                catch(InterruptedException exception)
                {
                    exception.printStackTrace();
                }
            } while(fldTerminates > 0);
        }
        Exception exception = fldException;
        if(exception instanceof IOException)
        {
            throw (IOException) exception;
        }
        if(exception instanceof CompilerException)
        {
            throw (CompilerException) exception;
        }
        if(exception instanceof RuntimeException)
        {
            throw (RuntimeException) exception;
        }
    }

    public final Object threadObject() {
        Hashtable objects = fldObjects;
        return objects == null ? null : objects.operator [](Thread.current());
    }

    public final int maxThreads { read = fldMaxThreads }

    public final ObjectArray targets { read = fldTargets, write = setTargets }

    protected void setTargets(ObjectArray newTargets) {
        if(fldContext != Thread.current())
        {
            throw new IllegalParallelWorkerState(package.getResourceString("parallelworker.modify"));
        }
        fldIndex = 0;
        fldTargets = newTargets;
    }

    final void terminate(Exception exception) {
        synchronized with(fldMonitor)
        {
            if(fldException == null) fldException = exception;
            if(--fldTerminates <= 0) notify();
        }
    }

    final Object nextTarget() {
        Object result = null;
        synchronized(fldMonitor)
        {
            if(fldException == null)
            {
                int index = fldIndex;
                ObjectArray targets = fldTargets;
                if(index < (targets == null ? 0 : targets.length))
                {
                    result = targets[index++];
                    fldIndex = index;
                }
            }
        }
        return result;
    }
}

final class CompilerParallelWorkerRunnable(Object, Runnable)
{
    private final CompilerParallelWorker fldParentWorker;
    private final CompilerRunnable fldHandler;

    public (CompilerParallelWorker parentWorker, CompilerRunnable handler) {
        fldParentWorker = parentWorker;
        fldHandler = handler;
    }

    public void run() {
        with(fldParentWorker) for(CompilerRunnable handler = fldHandler; ; )
        {
            Object target = nextTarget();
            if(target == null)
            {
                terminate(null);
                break;
            }
            if(handler != null) try
            {
                handler.run(target);
            }
            catch(Exception exception)
            {
                terminate(exception);
                break;
            }
        }
    }
}