Suvam Roy
Suvam Roy

Reputation: 953

Can't understand this multi-threading exception behavior

According to the documentation for ReentrantLock.newCondition(), the calling thread needs to own a lock before calling a signaling method:

If this lock is not held when any of the Condition waiting or signalling methods are called, then an IllegalMonitorStateException is thrown.

Indeed, this is what I see when I try it:

java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signalAll(AbstractQueuedSynchronizer.java:1954)
    at PingPongPrinter_.printPing(PingPong2.java:35)
    at WorkerPing.run(PingPong2.java:53)
    at java.lang.Thread.run(Thread.java:748)

So why do this restriction exists in java.util.concurrent.locks.ReentrantLock? I believe there is no such restriction in C++.

Upvotes: 0

Views: 82

Answers (1)

rgnt
rgnt

Reputation: 551

Answer to original question

You're unlocking a lock associated with the condition before signaling it. From documentation:

An implementation may (and typically does) require that the current thread hold the lock associated with this Condition when this method is called. Implementations must document this precondition and any actions taken if the lock is not held. Typically, an exception such as IllegalMonitorStateException will be thrown.

Also, only lock for the time required to modify the value you are conditioning for.

void printPong() throws Exception {

  // wait for pong condition
  while (isPing) {
    blockPong.await();
  }

  rlock.lock();
  isPing = true; // modify value
  blockPing.signalAll(); // signal ping
  rlock.unlock();
  
  System.out.println("Pong");
}

void printPing() throws Exception {

  // wait for ping condition
  while (!isPing) {
    blockPing.await();
  }

  rlock.lock();
  isPing = false; // modify value
  blockPong.signalAll(); // signal pong
  rlock.unlock();

  System.out.println("Ping");

}

Answer to modified question

So why do this restriction exists in java.util.concurrent.locks.ReentrantLock? I believe there is no such restriction in C++.

Because ReentrantLock is mutually exclusive. It provides access to one single thread at any given time. That's a design choice.

In C++ the std::condition_variable also requires you to own a mutex to the resource in order to signal.

Upvotes: 1

Related Questions