Skip to content

Instantly share code, notes, and snippets.

@josejuan
Created February 12, 2014 16:21
Show Gist options
  • Save josejuan/8958887 to your computer and use it in GitHub Desktop.
Save josejuan/8958887 to your computer and use it in GitHub Desktop.
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;
using System.IO;
using System.Security.Cryptography;
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<Tuple<string, string>> enumDirectoryHashes(string root) {
var q = new BlockingCollection<Tuple<string, string>>();
Func<SyncLink, IEnumerable<string>, bool> branchs = null;
Func<SyncLink, string, bool> node = (s, path) => {
if(File.Exists(path)) {
var hash = GetMD5HashFromFile(path); // éste se hace también en paralelo
s.End(() => q.Add(Tuple.Create(path, hash)), // sólo la escritura del resultado es sincrónica
() => false);
} else
branchs(s,
Directory.EnumerateFiles(path, "*.*", SearchOption.TopDirectoryOnly).Concat(
Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly))
.OrderBy(k => k)
);
return false; // podríamos calcular algún total sobre el árbol
};
branchs = (s, paths) => {
if(!paths.Any())
return s.End(() => { }, () => false); // nada que hacer
var head = paths.First();
var tail = paths.Skip(1);
if(!tail.Any())
return node(s, head);
// paralelización n-aria (como decía, basta ir añadiendo nodos
// para convertir un árbol binario en otro n-ario)
return s.Fork(() => { },
ss => node(ss, tail.First()),
ss => branchs(ss, tail.Skip(1)),
(a, b) => false);
};
new Thread(() => {
SyncLink.Run(s => node(s, root));
q.CompleteAdding();
}).Start();
return q.GetConsumingEnumerable();
}
static void hasdir(string path) {
Directory.EnumerateFiles(path, "*.*", SearchOption.TopDirectoryOnly).ToList().ForEach(f=>Console.WriteLine("{0}: {1}", GetMD5HashFromFile(f),f));
Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly).ToList().ForEach(d=>hasdir(d));
}
private static string GetMD5HashFromFile(string fileName)
{
try {
FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
} catch(Exception ex) {
return ex.Message;
}
}
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) {
// foreach(var hashedFile in enumDirectoryHashes(@"/home/josejuan"))
// Console.WriteLine("{0}: {1}", hashedFile.Item2, hashedFile.Item1);
hasdir(@"/home/josejuan");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment