[pc] folha de consulta - nac

2

Click here to load reader

Upload: nuno-cancelo

Post on 06-May-2015

131 views

Category:

Education


1 download

TRANSCRIPT

Page 1: [Pc]   folha de consulta - nac

Variáveis VolatileForma mais fraca de sincronização que garante a actualização de um valor na variável com propagação para as outras threads. Indica que se trata de uma variável partilhada e que operações sobre ela não devem ser reordenadas. Não são guardadas em registos ou caches, não ficando escondidas de outros processadores. Devem ser usadas para garantir a visibilidade do seu próprio estado, dos objectos a que se referem ou agirem como flag de sinalização.ConfinamentoForma de evitar sincronismo entre acessos a dados mutáveis não os partilhando. Os objectos Swing utilizam extensivamente esta técnica, uma vez que, apenas a thread de dispatch de eventos os pode manipular.ImmutabilityUm objecto imutável é aquele que não pode sofrer alterações de estado após a sua construção, que tem todos os campos final e que é construído correctamente (não há fuga do this). É diferente um objecto ser immutable e a referência para ele ser immutable. O uso da keyword final dá a garantia de iniciação segura.Estado de ExecuçãoO call e o prólogo são responsáveis por guardar em stack todo o estado de execução. Cada fio de execução guarda em stack uma foto de vários momentos da sua execução.Monitores : Brinch Hansen e HoareConceito de procs. de entrada (podem ser invocados fora do monitor) e procs. internos (apenas podem ser invocados pelos procedimentos de entrada). Existências de CV onde as threads se podem bloquear. Uma thread bloqueada numa CV executa logo que sinalizada, e, assim que esta sai do monitor a thread que a sinalizou executa. O estado do monitor é passado à thread sinalizada. Monitores : Lampson & RedellAlteração da semântica definida pelos monitores de Hoare: uma thread bloqueada na CV, quando sinalizada, passa para a fila de wait. Pode acontecer que uma outra thread ganhe o monitor (barging), tendo que ser avaliado o predicado por cada entrada no monitor. Possibilita três novas formas de acordar threads: timeout, interrupção e broadcast.Monitores : Diferenças entre Hoare e L&RL&R apresenta as vantagens de diminuir os context switches na sinalização (de dois para zero); permitir concelamento e interrupção; permitir barging aumentando as possibilidades de concorrência em sistemas multiprocessador. Desvantagem de não permitir a passagem de informação entre threads via monitor e de permitir o extravío de notificações. O extravío é possível quando uma thread é sinalizada, passa para a fila de wait depois cancelada, sendo que, caso não se capture a excepção e regenerada a notificação, esta será omitida.Monitores na CLI e na JVMImplicitamente todos os objectos têm associado um monitor, a associação só é feita no momento em que ocorre a primeira utilização. Garante-se a disponibilidade de monitores em pool diminuindo a utilização de memória. Cada monitor tem associada uma CV e permite re-entrância. Não é possível distinguir a threads bloqueadas na CV. Troca de informação entre threads feita através de variáveis de estado protegidas pelo monitor. Perca de notificações se ocorrerem em simultâneo com interrupção das threads. Não se pode assumir ordenação das threads. Monitores na CLI e na JVM - ImplicaçõesNecessidade de usar broadcast quando existem threads bloqueadas por mais do que uma razão; nas situações em que se usa notify é necessário capturar a excepção de interrupção para regenerar a notificação; critérios de ordenação obrigam à implementação explícita de filas de espera.Monitores JVMProcs. de entrada são métodos qualificados com synchronized. O método wait bloqueia a thread chamadora na CV pode lançar InterruptedException caso tenha expirado o timeout ou IlegalMonitorStateException caso não tenha sido obtido o lock do monitor. Os métodos notify e notifyall notificam uma ou todas as threads bloqueadas na CV.Monitores CLIManipulados através de métodos estáticos da classe Monitor. Recebem a referência para o objecto que define o monitor. Os métodos Enter e Exit permitem entrar e sair do monitor. O método TryEnter permite entrada cond.. O método Wait bloqueia a thread na CV. Pulse e PulseAll notificam uma ou todas as threads bloqs. A utilização destes métodos não garante a chamada ao Exit quando ocorre excepção. Para tal pode-se utilizar um bloco Lock.Cancelamento por DesistênciaA contabilização do timeout obriga a update da contagem de tempo, logo, obter uma ref. temporal antes do bloqueamento.Delegação de ExecuçãoResolve o problema criado pela possibilidade de barging nos monitores L&R. Não sendo possível um a thread sair do wait sem intromissão de outras threads, usa-se um request item com a info necessária. Permite alterar atomicamente estado partilhado.Notificação EspecíficaMétodo que permite tornar selectiva a notificação de threads, diminuindo o número de context switches, dada a não utilização de broadcast de notificação. A selectividade é atingida através da utilização de várias CV, específicas para cada predicado.Modelo de Acesso à Memória na JVMTodas as operações são feitas sobre a memória privada a thread. A escrita em memória partilhada é uma operação explícita release. A leitura através de

aquire.Publicação/VisibilidadeA publicação é tornar um objeto disponível a código fora do âmbito do mesmo (guardar uma referência onde o código -a pode encontrar, retornando-o de um método não privado, passando-o a um método de outra classe). Ao publicar incorretamente objetos outras threads podem obter referência null ou anterior á atual, ou obter referência válida, contudo, com conteúdo inválido. Construtor de Object escreve os valores por omissão nos campos do objeto antes do construtor da subclasse executar.Objectos mutáveis devem ser publicados correctamente. A publicação correcta de objectos tem que garantir que o estado deste, bem como a sua referência são tornadas visives ao mesmo tempo. Deve-se iniciar uma referência através de: initializer static; ref. num campo volatile, final ou num campo protegido por um lock.Uma das melhores formas é utilizar um iniciador estático, uma vez que são executados no construtor de tipo.Objectos immutable podem ser publicados a partir de qualquer mecanismo. Effectively immutable objects têm que ser publicados com segurança. Mutable objects têm que ser publicados com segurança e têm que ser thread-safe ou guardados por um lock.Threading na GUIActividade confinada à thread que faz o handle de eventos que são processados sequnc. Não se deve efectuar processamento nesta thread, sob pena de deixar de obter resposta do UI. A solução é criar uma outra thread, garantindo que a thread da event queue é quem actualiza os controlos. Existem os métodos estáticos (CLI) InvokeRequired (vê se é a thread owner do controlo), BeginInvoke (empilha um callback na event queue) e Invoke (empilha um callback na event queue e aguarda pelo término).TarefasActividades independentes que não dependem do estado, resultado ou de efeitos de outras tarefas. Podem ser executadas tarefas em paralelo, mediante os recursos disponíveis. E.g. num web server, é possível atender pedidos seq. (que degrada desempenho), ou criar uma thread por pedido (aumentando resposta do servidor permitindo atendimento em paralelo). Desvantagem de: pagar constantemente o overhead da criação de um thread; poderem ser criadas mais threads que CPU’s trazendo problemas de concorrência e de utilização excessíva de memória.JVM Executor FrameworkSuporta a execução asincrona de tarefas com variadas políticas de execução. Políticas de execução especificam: em que thread a tarefa será executada; ordem das tarefas; núm. tarefas concorrentes; núm. máximo em espera; algoritmo de rejeição; acções a serem tomadas antes e depois da execução da tarefa. Dependem dos recursos computacionais, bem como, da qualidade de serviço pretendida.JVM – ThreadPoolMecanismo que gere uma pool de worker threads. Tem associada uma fila de items de trabalho (tarefas) que são recolhidos por cada thread disponível para os executar. Vantagens: usa threads já existentes, reduzindo overhead de criação de threads diminuindo assim o tempo de resposta. Pode ter limite máximo de threads(FixedThreadPool); número variável dependendo dos recursos (CachedThreadPool); única thread para tratamento seq. de tarefas (SingleThreadExecutor); tamanho fixo para execução de tarefas periódicas ou agendadas tipo Timer (ScheduledThreadPool).JMM – Java Memory ModelA escrita de um valor em memória pode nunca ser vista, uma vez que: os compiladores podem reordenar instruções; guardar variáveis em registos/cache em vez de na memória; os processadores podem fazer processamento paralelo; alteração na ordem de escrita das caches para memória. O JMM abstrai os programador das diferenças dos modelos de memória das várias arquitecturas. Memory barriers (impedem que processadores e compiladores optimizem a partilha de dados entre threads) são determinadas identificando acesso a estado partilhado via sincronização. O JMM especifica actions que incluem leituras/escritas em variáveis, locks e unlocks de monitores e start e joins de threads. Define também uma ordenação parcial (chamada happens-before) em todas as acções.JMM – Happens-before relationNa ausência de uma ordenação happens-before o JMM é livre de ordenar. Excepção de objectos imutáveis, não é seguro usar um objecto iniciado por outra thread sem que exista uma relação happens-before com a thread que o vai consumir. É mais fiável, a nível de visibilidade e ordem do que safe-publication porque garante que a thread B vê a publicação correcta de X e de tudo o que A fez antes.JMM – Safe initiationUma forma de inciação lazy thread safe é através de um método public synchronized static iniciar um campo private static, contudo, em caso de utilização por muitas threads pode causar muita contenção. Outra forma é utilizar iniciadores estáticos uma vez que são executados pelo construtor de tipo. Construtor de tipo adquire um lock na construção e, esse lock é adquirido por todas as threads a fim de verificarem se o tipo está construído (relação happens-before). É garantido que em objectos contruídos correctamente, todas as threads conseguirão ver os valores de campos final ou de objectos por estes referenciados.IAsyncResultUma operação asincrona é lançada com BeginInvoke. A thread principal pode “fazer cenas” e depois: invocar EndInvoke (bloqueante até ao momento em que a tarefa assíncrona é terminada), com atenção para a chamada não ser feita em threads da GUI por exemplo; espera com WaitOne em WaitHandle, também bloqueante;

espera activa através da propriedade IsCompleted.Thread SafetyAtomicidade: Partilha de Dados. Garantir na leitura/escritaExplicit atomic operations. The class library provides a variety of atomic operations in the System.Threading.Interlocked class. These operations (e.g., Increment, Decrement, Exchange, and CompareExchange) perform implicit acquire/release operations.Acquiring a lock (System.Threading.Monitor.Enter or entering a synchronized method) shall implicitly perform a volatile read operation, and releasing a lock (System.Threading.Monitor.Exit or leaving a synchronized method) shall implicitly perform a volatile write operationVisibilidade: valores escritos por uma thread, são visíveis nas outras.Handling Thread SafetyImutabilidade: class final/sealedConfinamento: Todas as referencias devem estar confinadas à classe.Sincronismo: Monitores Intrinsecos, Memory ModelSincronizadores• Usar try, catch no utilização da primitiva wait• Utilizar class privada para guardar variáveis

globais, ou para delegação de execução ou como Future.

• Classes são final/sealed• variáveis são privadas, final• utilizar monitores intrínsecos• Usar sempre listas.

Notificação EspecificaMudança de Variável de condição. Esta classe é delegada a execução de uma thread especifica e não o monitor.class Condition { private readonly object _aLock; private readonly object _aWait; public Condition(object associatedLock){ _aLock = associatedLock;_aWait = this;}public Condition(object associatedLock, object associatedWait){_aLock = associatedLock;_aWait = associatedWait;}

private static ThreadInterruptedException enterMon(object _lock){ ThreadInterruptedException ie = null; do{try{Monitor.Enter(_lock);break;} catch(ThreadInterruptedException e){ie = e;} } while (true); return ie;}public void Wait(int timeout){ Monitor.Enter(_aWait); Monitor.Exit(_aLock); try{Monitor.Wait(_aWait, timeout);} finally{ThreadInterruptedException ie; Monitor.Exit(_aWait); if ((ie=enterMon(_aLock)) != null)throw ie; }}public void Wait(){Wait(Timeout.Infinite);}public void Notify(){ ThreadInterruptedException ie= enterMon(_aWait); Monitor.Pulse(_aWait); Monitor.Exit(_aWait); if (ie != null)Thread.CurrentThread.Interrupt();}public void NotifyAll(){ ThreadInterruptedException ie = enterMon(_aWait); Monitor.PulseAll(_aWait); Monitor.Exit(_aWait); if (ie != null)Thread.CurrentThread.Interrupt(); }}}Padrão de Confinamento na GUIO método verifica se está na thread owner do controlo. Problemas de aumento de context switches. If (ctrl.InvokeRequired) ctrl.BeginInvoke(delegate() { textBox1.text = txt; }) Return; Textbox1.text = txt;Métodos Synchronized em C#Utilização de atributo com semântica idêntica a JAVA.[MethodImpl(MethodImplOptions.Synchronized)] public Semaphore_FIFO(int initial) { if (initial > 0) permits = initial; }ParallelExecutepublic static int ParallelExecuteAndAdd(params Func<int>[] actions){ var countEv = new CountdownEvent(actions.Length); var res = new int[actions.Length]; int i = 0; foreach (var f in actions){ var func = f; int delta = i; ThreadPool.QueueUserWorkItem( delegate{ res[delta] = func.Invoke(); countEv.Signal(); } ); ++i; } while (!countEv.IsSet) countEv.Wait(); return res.Sum();}Parallel SignaturesParallel.For(int from, int to, Action<int> body);int sum = Parallel.Aggregate( 0, 10000, // domain 0, // initial value

Page 2: [Pc]   folha de consulta - nac

// Applied to each element delegate(int i){return (isPrime(i) ? i : 0) }, // Combine the element results delegate(int x, int y){ return x+y; } );Parallel.Do( delegate{ ParQuickSort(dom, lo, pivot - 1); }, delegate{ ParQuickSort(dom, pivot + 1, hi); });

Manual Reset Event com delegação de execuçãopublic class ManualResetEventCDE {private boolean _state;private ThreadRequest _mrecde;private final Object _monitor;public static class ThreadRequest{ public boolean _signaled; public int _counter;}public ManualResetEventCDE(){_state=false;_mrecde=null;_monitor = new Object();}public void Set(){synchronized (_monitor) { _state = true; if (_mrecde == null) return; _mrecde._signaled = true;_mrecde = null; _monitor.notifyAll();}}public void Reset(){synchronized (_monitor) {_state = false;} }public boolean WaitOne(long timeout) throws InterruptedException{synchronized (_monitor) { if(_state) return true; ThreadRequest mrecde = (_mrecde == null) ? _mrecde = new ThreadRequest() : _mrecde; mrecde._counter += 1;long lastTime = timeout == 0 ? 0: System.currentTimeMillis();try {while (true){_monitor.wait(timeout); if(mrecde._signaled) return true; if (timeout != 0) {long now = System.currentTimeMillis(); long elapsed = now - lastTime; if (elapsed >= timeout) return false; lastTime = now; timeout -= elapsed;}}}catch (InterruptedException ie) {if (_mrecde == mrecde && --mrecde._counter == 0){_mrecde = null;}throw ie;}}}}

Cyclic Barrierpublic final class CyclicBarrier {private final int _participants;private int _order;private final Object _cblock;private final Runnable _action;private Request _requests;public class Request{boolean _isBroken;boolean _isSignaled;}public CyclicBarrier(int participants){this(participants, null);}public CyclicBarrier(int participants, Runnable action){ if (participants < 0) throw new IllegalArgumentException(); _participants = participants; _cblock = new Object(); _order = 0;_action = action; }

public void Reset(){ synchronized (_cblock) {NotifyWaiters(false);}}public int Await() throws InterruptedException, BrokenBarrierException{synchronized (_cblock) { if (++_order == _participants){NotifyWaiters(true); if (_action != null) _action.run(); return _participants;}final int order = ++_order;Request myreq = _requests;try{while(true){ _cblock.wait(); if (myreq._isSignaled) return order; if (myreq._isBroken) throw new BrokenBarrierException();}}catch (InterruptedException ie){NotifyWaiters(false);throw ie;}}}public void NotifyWaiters(boolean signaled){if (signaled)_requests._isSignaled = true;else _requests._isBroken = true;_requests = new Request();_order = 0;_cblock.notifyAll();}}Bounded Queuepublic class BoundedQueue<T> {private final LinkedList<T> _buffer;private final LinkedList<TakeRequest<T>> _requests;private final int _capacity;private class TakeRequest<T>{public T _element;}public BoundedQueue(int capacity){_buffer = new LinkedList<T>(); _requests = new LinkedList<TakeRequest<T>>(); _capacity = capacity;}public void put (T elem) throws InterruptedException{synchronized (_buffer) { if(_buffer.size() != _capacity) {if (_requests.isEmpty()) {_buffer.addLast(elem);return;} TakeRequest<T> tr = _requests.removeFirst(); tr._element = elem;_buffer.notifyAll();return;}TakeRequest<T> tr = new TakeRequest<T>();tr._element = elem; _requests.addLast(tr);

try{while (true){_buffer.wait();if(tr._element == null) return;}}catch (InterruptedException ie){if(tr._element == null) {Thread.currentThread().interrupt();return;} _requests.remove(tr); throw ie;}}}public T take() throws InterruptedException{synchronized (_buffer) { if(!_buffer.isEmpty()) {T elem = _buffer.removeFirst(); if (!_requests.isEmpty()) {TakeRequest<T> tr = _requests.removeFirst(); _buffer.addLast(tr._element); tr._element = null; _buffer.notifyAll();} return elem;} TakeRequest<T> tr = new TakeRequest<T>(); _requests.addLast(tr); try{ while (true) {_buffer.wait(); if(tr._element != null) return tr._element;}} catch (InterruptedException ie) {if(tr._element != null){Thread.currentThread().interrupt(); return tr._element;}_requests.remove(tr);throw ie;}}}}Countdown Latchpublic class CountDownLatch {private int _counter;private final Object _latch;public CountDownLatch(int count){if (_counter < 0) throw new IllegalArgumentException();_counter = count;_latch = new Object();}public void CountDown(){synchronized (_latch) { if (_counter <= 0) throw new IllegalStateException(); _counter--; if (_counter == 0 ) _latch.notifyAll();}}public void Await() throws InterruptedException{ synchronized (_latch) { while (true){ if(_counter == 0)return _latch.wait();}}}}Transient Signalpublic final class TranscientSignal {private final Object _lock;public TranscientSignal(){_lock = new Object();}public boolean await(long timeout) throws InterruptedException{ synchronized (_lock){ long lastTime=timeout==0?0 : System.currentTimeMillis(); try{_lock.wait(timeout);if (timeout != 0){long now = System.currentTimeMillis();long elapsed = now - lastTime;if (elapsed >= timeout) return false;}return true;}catch (InterruptedException ie) {Thread.currentThread().interrupt();throw ie;}}}public void signalOne(){synchronized (_lock) {_lock.notify();}}public void signalAll(){synchronized (_lock) {_lock.notifyAll();}}}SemaphoreFifoSNpublic sealed class Semaphore_FIFO_SN{private int permits = 0;private readonly LinkedList<int> queue = new LinkedList<int>();public Semaphore_FIFO_SN(int initial){if (initial > 0)permits = initial;}private void notifyWaiter(){if (queue.Count > 0 && permits >= queue.First.Value) SyncUtils.Notify(this, queue.First);}public bool Acquire(int n, int timeout){lock (this){if (queue.Count == 0 && permits >= n){permits -= n;return true;}LinkedListNode<int> rn = queue.AddLast(n);int lastTime = (timeout != Timeout.Infinite) ?Environment.TickCount : 0;do{try{SyncUtils.Wait(this, rn, timeout);}catch (ThreadInterruptedException){queue.Remove(rn);notifyWaiter();throw;}if (rn == queue.First && permits >= n){queue.Remove(rn);permits -= n; notifyWaiter();return true;}if (SyncUtils.AdjustTimeout(ref lastTime, ref timeout) == 0){queue.Remove(rn);notifyWaiter(); return false;}} while (true);}}public void Acquire(int n){Acquire(n, Timeout.Infinite);}public void Release(int n){lock (this){permits += n;notifyWaiter(); }}}}public class AsyncResultM : IAsyncResult { private readonly ManualResetEvent handle; private volatile bool isCompleted; AsyncM readonly obj; Exception exception; string readonly a1; int readonly a2; int a3; int a4;bool CompletedSynchronously{get{return false;}}WaitHandle AsyncWaitHandle{get{return handle;}}object AsyncState { get { return isCompleted;}}boolean IsCompleted(){ return isCompleted;}AsyncResultM (string a1, int a2, int a3, int a4, object ob){ obj = ob; thia.a1 = a1; thia.a2 = a2; this.a3 = a3;

this.a4 = a4; ret = null; exception = null; handle = new ManualResetEvent();}public void PublishResults() { isCompleted = true;handle.WaitHandle.Set();}}delegate int AsyncM (string a1, int a2, ref int a3, out int a4)public class AsyncM{public int M (string a1, int a2, ref int a3, out int a4){// Invocação sincrona}public IAsyncResult BeginM (string a1, int a2, ref int a3, out int a4){AsyncResultM res = new AsyncResultM(a1, a2, a3, a4, this);executor.Execute( delegate() {try { res.ret = res.obj.M (res.a1, res.a2, ref res.a3, out res.a4); }catch (Exception e) { res.exception = e; }res.PublishResults();});return res;}public int EndM (IAsyncResult iar, ref int a3, out int a4){AsyncResultM iarm = iar as AsyncResultM;if (iarm == null) throw new ArgumentNullException();if (!iar.IsCompleted)iarm.WaitHandle.WaitOne();if (res.exception != null)throw res.exception;a3 = iarm.a3;a4 = iarm.a4;return iarm.ret;}}ParallelForpublic static void ParallelFor(int startIdx, int endIndex, Action<int> body){int threadCount = Environment.ProcessorCount;int blockSize = (endIndex - startIdx + 1)/threadCount;var latch = new CountdownEvent(threadCount);for(int count = 0; count < threadCount; ++count){ThreadPool.QueueUserWorkItem((state) =>{int pid = (int) state;int start = pid * blockSize;for (int idx = start; idx < start + blockSize && idx < endIndex; ++idx) body(idx); latch.Signal(1);}, count);}latch.Wait();}Adjust Timeoutpublic static int AdjustTimeout(ref int lastTime, ref int timeout) { if (timeout != Timeout.Infinite) { int now = Environment.TickCount; int elapsed = (now == lastTime) ? 1 : now- lastTime; if (elapsed >= timeout) { timeout = 0; } else {timeout -= elapsed; lastTime = now; } } return timeout; } Simple Background Workerpublic abstract class SimpleBackgroundworker {private Object _result;private final Object _lock;public abstract Object doInBackground() throws Exception;public abstract void done();public SimpleBackgroundworker(){_result = new Object();_lock = new Object();}public final void execute(){new Thread(new Runnable() { public void run() {try {Object result = doInBackground();synchronized (_lock) {_result = result;}} catch (Exception e) {synchronized (_lock) {_result = e;}}EventQueue.invokeLater(new Runnable() {public void run() {done();}});}}).start();}public final Object get() throws Exception{while(true){synchronized (_lock) {if (_result instanceof Exception) throw (Exception) _result;return _result;}}}public final boolean isDone(){synchronized(_lock){return !(_result == null);}}}ThreadPoolpublic final class NThreadPoolExecutor implements Executor {private LinkedList<Runnable> _queue;public NThreadPoolExecutor(int nThreads) throws InterruptedException{ _queue = new LinkedList<Runnable>(); while (nThreads-- != 0){ (new Thread() {public void run() { try { threadAction(); } catch (InterruptedException _) {}}}).start(); }} public void execute(Runnable action) { synchronized (_queue){_queue.addLast(action);}} public void shutdown(){} public void threadAction() throws InterruptedException{while(true){ Runnable action = null; synchronized (_queue){ if(!_queue.isEmpty()) action = _queue.remove(); else _queue.wait(); } if(action != null) try{ action.run(); } catch (Throwable _){} }}}