2009-08-03 41 views
13

Có thể semaphore thấp hơn 0 không? Tôi có nghĩa là, nói rằng tôi có một semaphore với N = 3 và tôi gọi là "xuống" 4 lần, sau đó N sẽ vẫn 0 nhưng một quá trình sẽ bị chặn?Cách hoạt động của semaphore?

Và cùng một cách khác, nếu ban đầu tôi gọi, N có thể cao hơn 3? Bởi vì như tôi thấy nó, nếu N có thể cao hơn 3 nếu ban đầu tôi gọi lên vài lần, sau đó tôi có thể gọi nhiều lần hơn tôi có thể, do đó đưa thêm quy trình vào phần quan trọng sau đó semaphore cho phép tôi .

Nếu ai đó sẽ làm rõ nó một chút cho tôi, tôi sẽ đánh giá cao.

Greg

+0

Xem thêm http://stackoverflow.com/questions/184147/countdownlatch-vs-semaphore – finnw

Trả lời

6

Calling xuống khi đã ghi bàn 0 không nên làm việc. Gọi điện khi nó hoạt động 3. (Tôi đang nghĩ đến Java).

Hãy để tôi thêm một số chi tiết. Nhiều người nghĩ rằng các khóa như (nhị phân) semaphores (tức là - N = 1, vì vậy giá trị của semaphore là 0 (được giữ) hoặc 1 (không được giữ)). Nhưng điều này không hoàn toàn đúng. Khóa có khái niệm "quyền sở hữu" để nó có thể là "reentrant". Điều đó có nghĩa là một sợi có khóa, được phép gọi khóa() một lần nữa (di chuyển hiệu quả số đếm từ 0 đến -1), bởi vì luồng đã giữ khóa và được phép "nhập lại" nó. Khóa cũng có thể không reentrant. Một người giữ khóa dự kiến ​​sẽ gọi mở khóa() cùng số lần như khóa().

Các ẩn dụ không có khái niệm về quyền sở hữu, vì vậy chúng không thể được cấp lại, mặc dù có thể có được nhiều giấy phép. Điều đó có nghĩa là một luồng cần chặn khi nó gặp giá trị bằng 0, cho đến khi ai đó gia tăng semaphore.

Ngoài ra, trong những gì tôi đã thấy (là Java), bạn có thể tăng semaphore lớn hơn N, và đó cũng loại phải làm với quyền sở hữu: một Semaphore không có khái niệm quyền sở hữu để ai cũng có thể cho nó nhiều hơn giấy phép. Không giống như một chuỗi, trong đó bất cứ khi nào một chuỗi gọi mở khóa() mà không cần giữ khóa, đó là lỗi. (Trong java nó sẽ ném một ngoại lệ).

Hy vọng cách suy nghĩ này giúp ích.

16

(Sử dụng các thuật ngữ từ java.util.concurrent.Semaphore trao thẻ Java. Một số các chi tiết có thực hiện cụ thể. Tôi nghi ngờ của bạn "xuống" là phương pháp semaphore Java acquire(), và bạn "up" là release().)

Có, cuộc gọi cuối cùng của bạn tới acquire() sẽ chặn cho đến khi một chuỗi khác gọi release() hoặc chuỗi của bạn bị gián đoạn.

Có, bạn có thể gọi release() lần nữa, sau đó giảm nhiều lần - ít nhất với java.util.concurrent.Semaphore.

Một số triển khai khác của semaphore có thể có ý tưởng về số lượng giấy phép "tối đa" và cuộc gọi phát hành vượt quá mức tối đa đó sẽ không thành công. Lớp Java Semaphore cho phép tình huống đảo ngược, trong đó semaphore có thể bắt đầu với số lượng giấy phép âm và tất cả các cuộc gọi acquire() sẽ không thành công cho đến khi có đủ số cuộc gọi release(). Khi số lượng giấy phép đã trở thành không âm, nó sẽ không bao giờ trở thành tiêu cực nữa.

+0

Có an toàn khi nói hành vi Semaphore phủ định như chốt đếm không? Hiệu quả tôi không thể làm bất cứ điều gì khi phát hành cuối cùng (Count = 0) đạt được. Hoặc là có bất kỳ usecase khác, nơi tôi sẽ muốn sử dụng một semaphore tiêu cực? – jtkSource

+0

@jtkSource: Tôi không biết một người nào. –

1

Chỉ cần xem N làm bộ đếm đếm tài nguyên giới hạn của bạn. Vì bạn không thể có số lượng tài nguyên âm, N vẫn còn> = 0. Nếu số lượng tài nguyên sẵn có của bạn thay đổi, số N tối đa cũng phải được thay đổi. Tôi wouln't xem xét nó phong cách tốt để tăng n mà không cần decrementing nó đầu tiên trong bất kỳ trường hợp khác.

2

Có, giá trị âm có nghĩa là bạn có các quy trình chờ cho semaphore được phát hành. Một giá trị tích cực có nghĩa là bạn có thể gọi thu được nhiều lần trước các khối semaphore.

Bạn có thể nghĩ về giá trị theo cách này: một số dương nghĩa là có nhiều tài nguyên có sẵn. Giá trị âm có nghĩa là có nhiều thực thể cần một tài nguyên khi tất cả các tài nguyên được thực hiện tại thời điểm này. Khi bạn có được một tài nguyên bạn giảm giá trị, khi bạn giải phóng nó, bạn tăng giá trị. Nếu giá trị vẫn còn> = 0 sau khi giảm, bạn sẽ nhận được tài nguyên, nếu không thì thực thể của bạn được đưa vào hàng đợi.

Một lời giải thích tốt đẹp của Cột trong Wikipedia: http://en.wikipedia.org/wiki/Semaphore_(programming)

8

Hi Greg xem xét sau Ví dụ:

public static void main (String [] args) throws InterruptedException {

Semaphore available = new Semaphore(1, true); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 
} 

Nếu bạn thấy đầu ra u sẽ nhận được như sau:

Acquire: 0 Đã phát hành: 1 Đã phát hành: 2 Đã phát hành: 3 Đã phát hành: 4 Có được: 3 Có được: 2 Có được: 1 Có được: 0 Và chờ đợi đang diễn ra.

Vì vậy, về cơ bản cho phép sẽ tăng trên mỗi bản phát hành và mua lại sẽ giảm nó đến 0. Khi nó đạt đến 0 nó sẽ đợi cho đến khi phát hành được gọi là trên cùng một đối tượng :)

0

Sử dụng java.util.concurrent.Semaphore với phương thức get() và release(), tôi nghĩ rằng giấy phép sẽ luôn là> = 0. Giả sử bạn muốn đồng bộ hóa các chuỗi sao cho chỉ có 1 luồng có thể nằm trong vòng lặp. Nếu sem là loại Semaphore có giá trị ban đầu 1, điều này sẽ không làm việc cho hơn 2 chủ đề.

while(true){    

    sem.wait(); // wait is acquire 

    for(int i=0; i<=5; i++){ 

     try { 
      Thread.sleep(250); 
     }catch (InterruptedException e) {} 

     System.out.println("Thread "+ threadname+ " " + i); 

      } 
    sem.signal(); // signal is release } 

Tuy nhiên, bạn có thể triển khai lớp Semaphore từ java và tạo lớp của riêng bạn cho phép điều này.

package yourpackage; 

import java.util.concurrent.Semaphore; 

public class SemaphoreLayer { 
public Semaphore s=null; 
public String name; 
private int val; 

public SemaphoreLayer(int i){ 
    s=new Semaphore(i); val=i; 
} 

public void wait(){ 
try { 
    val--; 
    s.acquire(); 

    } catch (InterruptedException e) { 
    System.out.println("Error signal semaphorelayer"); 
}} 

public void signal(){ 
    if(val<0){val++;}{ 
     s.release(); 
     val++; 
    } 
} 

} 

Giá trị hiện tại có thể âm. Tuy nhiên, tôi không chắc chắn rằng điều này là hoàn toàn an toàn, bởi vì nếu chúng ta có tín hiệu từ một sợi và chờ đợi từ khác và họ cố gắng val + + và val-- điều này có thể là xấu. (cơ hội cho điều này là rất nhỏ nhưng stil họ tồn tại, vì vậy nếu bạn đang mã hóa và bạn phải được 100% không có lỗi, tôi không khuyên bạn nên sử dụng mã này) Kết luận đây là lý do tại sao nó là tốt hơn để sử dụng khái niệm của màn hình trong java và từ khóa được đồng bộ hóa.