Alright so given this graph that must be implemented with the minimum number
of semaphores , I’d like to know when does an edge is considered redundant and should be
removed, in my example can the edge from (2) to (5) be considered redundant (why)
I’ve also have to specify that the graph is not cyclic and you cannot use the cobegin-coend construct
So my dilemma rounds around the redundant edges because that modifies my solution, until now I think
that (2)–(5) can be kept and I’d divide the semaphores in this order :
s1 (from 1 to 2 , 3 and 5)
s2 (from 2 and 3 to 4)
s3 (from 1 , 2 and 3 to 5)
s4 (from 3 , 4 and 5 to 6)

@karmastan
consider the semaphore primitives signal() and wait() and consider this graph (1)–s1–>(2) therefore to arrive to (2) you should use a semaphore “s1” on the edge from (1) to (2) and you must first execute (1) so the code would be something like
1 : 2:
do (1) wait(s1) //waits for the signal from 1
signal(s1)//1 has finished do (2)
@Jean-Bernard
I understand, so if I get the concept right in this example where the “dotted” edges
are to be considered in Mutual Exclusion (beside the usual semaphore implement also a mutex)

therefore
I should remove :
(1)---->(6) //because it's a "cross" edge
(3)---->(6) // also because it's a "cross" and excludes (3)--->(5)
then I would have 6 semaphores and a mutex
s1 (from 1 to 2)
s2 (from 1 to 3)
s3 (from 1 to 4)
s4 (from 2 and 3 to 5)
s5 (from 4 and 5 to 6)
s6 (from 6 to 1)
mutex(between 2 and 4)
1 -> 2 and 3
2 and 3 -> 4 and 5
4 and 5 -> 6
The longest path is 3, so it should reason that you could do it with 3 semaphores.
Vertices should be results at the semaphore corresponding to the longest path from source. And prereqs should be the edges leading into the results that come from the longest path available.
The wording of the above is confusing, but what it means is that 1->5 was eliminated because that edge is a level 1 edge (comes from source), but 5 is a level 2 node(has a max path from source to it of length 2). Same process eliminates 3->6.
You can’t eliminate 2->5 because it is a level 2 path leading to a level 2 node. If it was a level 1 path, or 5 was a level 3 node, then you could because some other semaphore would have handled the prerequisites for 5.
Consider your graph with edges added from 2->1 and 6->3. (This means you can perform 1 once, then 2 needs to happen before you can repeat 1, likewise for 3 and 6.)
1, then appears as a result on level 2 because the longest path leading into 2 is length 2 : needing no additional semaphore for 2->1
note: this doesn’t mean 1 appears as a prereq for level 3, this fits with the definitions I gave, but the previous example had matching prereqs to results, which was just coincidence, so I thought I’d point it out.
Now you also have the path from 6->1 to consider. This path is of length 4 from the source, and is not already explored. So it needs an additional semaphore since it means we have a 4th level. This 4th level is simply a semaphore from 6->1, because those are the only unexplored length 4 paths. Once an edge has been traversed, you can ignore it from that point on.
So making a graph cyclic doesn’t make it that much harder. Things are still on “levels” and can’t appear as a result or prereq for more than one level. The only thing that we need to take into account that we didn’t need to before, is that once an edge is traversed you ignore it, this avoid infinite loops with a cyclic graph, and just wasn’t necessary previously.