#1

Binary Semaphore: S1_a, S1_b, S2_a, S2_b, S3, S4_a, S4_b, S4_c, S5, S6, S7, S8

P1:    P1 operations;
         S1_a.V();
         S1_b.V();

P2:    P2 operations;
         S2_a.V();
         S2_b.V();

P3:    S1_a.P();
         S2_a.P();
         P3 operations;
         S3.V();

P4:    S1_b.P();
         S2_b.P();
         P4 operations;
         S4_a.V();
         S4_b.V();
         S4_c.V();

P5:    S4_a.P();
         P5 operations;
         S5.V();

P6:    S4_b.P();
         P6 operations;
         S6.V();

P7:    S4_c.P();
         P7 operations;
         S7.V();

P8:    S3.P();
         S5.P();
         P8 operations;
         S8.V();

P9:    S6.P();
         S7.P();
         S8.P();
         P9 operations;
 

#2

Producer
    //Produce item
    P(mutex);
    P(empty);
    //CS
    V(mutex);
    V(full);

Consumer
    P(mutex);
    P(full);
    //CS
    V(mutex);
    V(empty);
    //Consume item

As can be seen above, with the exchange of wait(empty) and wait(mutex) in the producer and wait(full) and wait(mutex) in the consumer, deadlock can easily occur in the following two situations:

(1) When full = n and empty = 0 and producer reaches mutex first, it will wait for consumer to consume one or more items, which will not happen because consumer is blocked out of mutex.
(2) When full = 0 and empty = n and consumer reaches mutex first, it will wait for producer to produce one or more items, which again will not happen because producer is blocked out of mutex.
#3

Bounded_Semaphore: Monitor
    var s: integer;
    var c1, c2: condition;

procedure P()
    begin
        if (s <= 0) c1.wait();
        s--;
        c2.signal();
    end

procedure V()
    begin
        if (s >= smax) c2.wait();
        s++;
        c1.signal();
    end

//Initialization code
begin
    s = smax;
end