0votos

Flujo sincrónico dentro de un árbol de procesos concurrentes no deterministas en C#

por josejuan hace 5 años

Usando semáforos.

Si un proceso inicia procesos concurrentes no deterministas y éstos a su vez inician otros, podemos "dibujar" el árbol de procesos generado y el orden en el que ésto ocurre. Se pide programar un entorno (¿API?) que permita recuperar de forma sincrónica cierto producto (ej. un log) de los procesos concurrentes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using System; 
using System.Collections; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
 
namespace forkf { 
 
    public class SyncLink { 
 
        private Semaphore _win, _wou; 
 
        private SyncLink(Semaphore win, Semaphore wou) { 
            _win = win; 
            _wou = wou; 
 
        // ésta es la acción pospuesta del cuadrado VERDE 
        private static void delaySync(Semaphore win, Semaphore wou, Action syncAction) { 
            new Thread(() => {    // Dejaremos en el aire... 
                win.WaitOne();    // ...esperando al anterior en la lista... 
                syncAction();     // ...la acción que lanzaremos... 
                wou.Release();    // ...antes de darle paso al siguiente en la lista. 
            }).Start(); 
 
        // inicia una ejecución paralela de un árbol con flujo sincrónico 
        public static C Run<C>(Func<SyncLink, C> root, bool wait = false) { 
            var w = new Semaphore(0, 1); 
            var r = root(new SyncLink(new Semaphore(1, 1), w)); 
            if(wait) // permite sincronizar el flujo VERDE y el AZUL (o no) 
                w.WaitOne(); 
            return r; 
 
        // las hojas del árbol cierran el circuito, tras efectuar su acción sincronizada 
        public C End<C>(Action syncAction, Func<C> end) { 
            delaySync(_win, _wou, syncAction); 
            return end(); 
 
        // la operación de división, creamos dos semáforos intermedios para formar el enlace sincronizado 
        public C Fork<A, B, C>(Action syncAction, Func<SyncLink, A> left, Func<SyncLink, B> right, Func<A, B, C> join) { 
 
            var u = new Semaphore(0, 1); 
            var v = new Semaphore(0, 1); 
 
            // cuadrado verde 
            delaySync(_win, u, syncAction); 
 
            // cuadrado azul 
            A ra = default(A); 
            B rb = default(B); 
 
            var a = new Thread(() => ra = left(new SyncLink(u, v))); 
            var b = new Thread(() => rb = right(new SyncLink(v, _wou))); 
 
            a.Start(); 
            b.Start(); 
 
            a.Join(); 
            b.Join(); 
 
            return join(ra, rb); 
 
 
    class Program { 
 
        static int fibonacci(SyncLink s, int n, Action<int> action) { 
 
            Thread.Sleep(1000); 
 
            if(n < 2) 
                return s.End(() => action(n), () => 1); 
 
            else 
                return s.Fork(() => action(n) 
                        , ss => fibonacci(ss, n - 1, action) 
                        , ss => fibonacci(ss, n - 2, action) 
                        , (a, b) => a + b); 
 
 
 
 
        static IEnumerable<int> enumerableFib(int N) { 
            var q = new BlockingCollection<int>(); 
            new Thread(() => { 
                SyncLink.Run(s => fibonacci(s, N, n => q.Add(n))); 
                q.CompleteAdding(); 
            }).Start(); 
            return q.GetConsumingEnumerable(); 
 
 
        static void Main(string [] args) { 
 
            var r = SyncLink.Run(s => fibonacci(s, 4, n => Console.WriteLine(n)), true); 
 
            Console.WriteLine("Fibonacci: {0}", r); 
 
            Console.WriteLine("==========="); 
            foreach(var n in enumerableFib(4)) 
                Console.WriteLine("e ~> {0}", n); 
 
 
 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.