Semafor priorytetowy - monitor notify nie dochodzi

0

Mam następujący problem, możliwe, że popełniłem błąd i go po prostu nie widzę, ale to co obserwuje, jest dla mnie dziwne. Pomimo, że proces śpi na jakimś obiekcie monitorze, to inny wątek wysyłający do niego powiadomienie za pomocą notify na tym samym obiekcie nie zawsze budzi go.

To jest bardzo losowe, by to zaobserwować (deadlock) należy bez żadnych opóźnień itd. - kręcenie się w kółko dawać operacje aquire i release. Nie zawsze się to zwiesza, ale czasami tak (co dla mnie jest niedopuszczalne).

Rozwiązaniem jakie teraz stosuje (by przebadać te zjawisko - należy to zakomentować tymczasowo w kodzie) Thread.interrupt na tym wątku, to zawsze działa i nie deadlockuje.

Czy tak może być, że notify nie dotrze do jedynego obiektu czekającym na monitorze? Czy to zwykły programistyczny bug (prosiłbym o wskazanie go, jak ktoś go znajdzie)

kod:

package tpsa.concurrency;

import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrioritySemaphore {

	private Lock lock;
	private ArrayList<SemaphoreObject> threads;
	private int counter;

	public PrioritySemaphore(int counter) {
		lock = new ReentrantLock(true);
		threads = new ArrayList<>();
		this.counter = counter;
	}

	public void aquire() {
		lock.lock();
		counter--;

		if (counter < 0) {
			SemaphoreObject l = new SemaphoreObject();
			l.t = Thread.currentThread();
			
			int idx = 0;
			for (idx = 0; idx < threads.size(); idx++) {
				if (threads.get(idx).t.getPriority() < l.t.getPriority())
					break;
			}
		
			threads.add(idx, l);
		

			lock.unlock();

			synchronized (l) {
						try {
							l.wait();
						} catch (InterruptedException e) {
							
						}
						
						Thread.currentThread().isInterrupted();
						
						
			}
			
		} else
			lock.unlock();

	}

	public void release() {
		lock.lock();

		counter++;

		SemaphoreObject tFirst = (threads.size() > 0) ? threads.get(0) : null;

			if (tFirst != null) {
				synchronized (tFirst) {
					tFirst.t.interrupt();
				}
				threads.remove(tFirst);
			}

		lock.unlock();
	}

}

package tpsa.concurrency;

public class SemaphoreObject {
	
	public Thread t;
	public int priority;
	
	public SemaphoreObject()
	{
		t = null;
		priority = 1;
	}
	
	@Override
	public String toString() {
		return t.getName() + "(" + priority + ")";
	} 

}
0

Mieszanie monitorów i ręcznych locków to proszenie sie o guza. Poza tym nie widzę w tym kodzie w ogóle notify za to widzę synchronize i wait na lokalnym (!) obiekcie. WTF?

0

Czy tak może być, że notify nie dotrze do jedynego obiektu czekającym na monitorze? Czy to zwykły programistyczny bug (prosiłbym o wskazanie go, jak ktoś go znajdzie)

Nie może.
U ciebie deadlock powstaje wtedy gdy jeden wątek zawołał acquire i doszedł do l.wait(); ale jeszcze nie zaczął go wykonywać. Drugi wątek woła wtedy release, który wykonuje notify. Pierwszy wątek jeszcze nie zaczął czekać więc notify jest "gubiony".
W twoim przypadku interrupt() to naprawia ale to raczej hak a nie rozwiązanie. Do tego masz zupełnie bezsensowną linijke: Thread.currentThread().isInterrupted();, która nie robi nic. Pewnie chodziło o Thread.interrupted().

1 użytkowników online, w tym zalogowanych: 0, gości: 1