我如何防止我的程序陷入僵局但仍然保持相互排斥? (信号量)

时间:2016-04-19 22:05:29

标签: java multithreading semaphore

目前正在使用信号量和线程处理操作系统类的Homework问题。非常困惑,并想知道这里是否有人可以提供帮助。我到目前为止的代码:

01 travelToShop();    //puts thread to sleep between 1 and 1000 cycles
02 s1.acquire();      //lock semaphore, keeps mutual exclusion so no other
03 //thread writes to variable while another one is trying to do the same
04
05 if (numofcust==5){    //cant have more then 5 customers in a "shop"
06  s2.acquire();     //lock the shop, wait until shop reopens
07 }
08 numofcust++;          //increases variable telling class how many in shop
09 arriveAtShop();       //print statement saying ive arrived, if i arrived
10 //im technically in shop
11
12 s1.release();      //done writing to numofcust
13 sittingInShop();  //puts thread to sleep between 1 and 1000 cycles
14 //simulating having coffee
15
16 s1.acquire();     //refer to last "s1.acquire()"
17 numofcust--;      //simulating leaving the shop
18 if (numofcust==0){ //if shop empty
19 s2.release();     //open the shop
20 }
21 leaveShop();
22 s1.release();    //refer to last "s1.release()"    

我知道问题在于第6和第12行。一旦商店中有5个顾客,其余的顾客必须等待(第6行)。因为我必须等待,第一个持有s1的人持有另一个客户必须获取的信号量才能离开(因此没有线程可以释放线程正在等待的锁定以便该线程释放锁定某人离开。

我尝试过以下操作:

05 if (numofcust==5){    //cant have more then 5 customers in a "shop"
06 s1.release(); //release the lock so others can write to numofcust and read
07  s2.acquire();     //lock the shop, wait until shop reopens
08  s1.acquire();    //reacquire the lock so i can write to numofcust again
09 }

然后我打破了互斥

如果没有锁定没有人可以写入numofcust,我如何保持互斥,但是防止一个线程持有锁定到numofcust的死锁,因为它是等待直到商店打开的?

编辑:如果店内有5位顾客,店外的所有顾客都要等到他们全部离开,但如果顾客少于5位,他们可以随意进入

2 个答案:

答案 0 :(得分:1)

你不需要两个信号量。 Semaphore对象可以具有可变数量的许可。在有许可证的情况下,可以多次获取信号量。只有在获得所有许可证后,信号量才会阻塞。如果随后释放许可证,则被阻止的线程可以唤醒获取新获得的许可证。

许可不归线程所有。任何线程都可以释放任意数量的许可。这为您在发放许可证时提供了很大的灵活性。

离开时,您需要根据已输入的人的高水印来更改许可证的发布方式。当高水位小于5时立即释放。当高水位标记为5时,等到最后一个人离开然后释放所有许可证。这意味着将商店中的人数分别计算到信号量许可,并在达到5时设置一个标志。计数和标志需要一次更新并仅由一个线程检查。

答案 1 :(得分:0)

@MattChampion的答案很好,但我只想指出解决问题的方法通常不止一种。

解决此问题的另一种方法是,如果您无法使用Semaphore类,则使用BlockingQueue

在程序开头的阻塞队列中放入五个“令牌”。令牌可以是任何对象。 (例如,Object token = new Object();)然后,确保每个客户线程在进入商店之前从队列中获取一个令牌,并在离开商店后将令牌返回到队列。

如果一个线程在队列为空时尝试获取一个令牌(五个客户在商店中),它将被阻止,直到一个令牌可用。

阻塞队列是一种强大的抽象,除了只是一个将对象从一个线程传递到另一个线程的管道之外,它可以在很多方面使用。