Orario: 24-05-2013, 19:14 Benvenuto ospite! (Log inRegistrati)


Rispondi 
Parere
Autore Messaggio
TheQult
Subconscio

Messaggi: 129
Registrato: Jul 2010
Offline Offline
#1 Parere
0
Cio bisogno di una collezione concorrente e no non posso usare .net 4, quindi di necessita' virtu me la sono scritta.
Ho optato per una semplice lista visto che tanto quelle che devo fare sono interrogazioni Linq e non potendo sapere a prescindere cose facciano e su che campi lo facciano dovrei cmq farle girare su tutta la collezione.
So per sicuro che ci saranno degli errori ma essendo che sono poco lucido e che e' una settimana che me lo meno dietro a questo coso confido nel vostro occhio vigile, specie sulle lock.
I valori sono volutamente deep-copiati prima di essere restituiti

Codice:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

using CSPages;
using CSPages.IO;

namespace Emitter
{
    class Table<T> : IEnumerable<T>
    {
        class Enumerator : IEnumerator<T>
        {
            Table<T> table;
            LinkNode node;

            public Enumerator(Table<T> table)
            {
                this.table = table;
                this.node = table.Root;
            }

            T IEnumerator<T>.Current
            {
                get
                {
                    T ret = default(T);

                    lock (this.node)
                    {
                        ret = this.node.Value;
                    }
                    return ret;
                }
            }

            void IDisposable.Dispose()
            {
                lock (table)
                {
                    Interlocked.Decrement(ref table.enumerators);
                }
            }

            object System.Collections.IEnumerator.Current
            {
                get
                {
                    T ret = default(T);

                    lock (this.node)
                    {
                        ret = this.node.Value;
                    }
                    return ret;
                }
            }

            bool System.Collections.IEnumerator.MoveNext()
            {
                bool ret = false;
                lock (this.node.next)
                {
                    if (this.node.next != LinkNode.Empty)
                    {
                        this.node = this.node.next;
                        ret = true;
                    }
                }
                return ret;
            }

            void System.Collections.IEnumerator.Reset()
            {
                lock (this.node)
                {
                    this.node = table.Root;
                }
            }
        }

        class LinkNode
        {
            private T value;
            public T Value
            {
                get
                {
                    T ret = default(T);
                    lock (this.value)
                    {
                        ret = this.value.DeepClone();
                    }
                    return ret;
                }
                set
                {
                    lock (this.value)
                    {
                        this.value = value;
                    }
                }
            }
            public LinkNode next;

            public readonly static LinkNode Empty = new LinkNode();

            public LinkNode()
            {
                this.next = this;
                this.value=default(T);
            }

            public LinkNode(T value)
            {
                this.value = value;
                next = Empty;
            }
        }

        int enumerators;

        LinkNode Root;
        
        LinkNode Tail;

        public Table(string path)
        {
            enumerators = 0;
            Root = LinkNode.Empty;
            Tail = Root;
        }

        public void Add(T obj)
        {
            bool ret =  false;
            lock (Root)
            {
                if (Root == LinkNode.Empty)
                {
                    Root = new Table<T>.LinkNode(obj);
                    lock (Tail)
                    {
                        Tail=Root;
                    }
                    ret = true;
                }
            }

             if (ret)
                return;

            lock (Tail)
            {
                lock (Tail.next)
                {
                    Tail.next = new Table<T>.LinkNode(obj);
                }
                Tail = Tail.next;
            }
        }

        public void Clear()
        {
            lock (Root)
            {
                Root = LinkNode.Empty;
            }
            lock (Tail)
            {
                Tail = Root;
            }
        }

        public int Update(Func<T, T> row, Func<T, bool> where)
        {
            int affected=0;
            LinkNode node;

            lock (Root)
            {
                node = this.Root;
            }

            lock (node)
            {
                while (node != LinkNode.Empty)
                {
                    T val = node.Value;

                    if (where.Invoke(val))
                    {
                        node.Value = row.Invoke(val);
                        affected++;
                    }
                    lock (node.next)
                    {
                        node = node.next;
                    }
                }
            }
            return affected;
        }

        public int Delete(Func<T, bool> where)
        {
            int affected = 0;

            LinkNode before=null;
            LinkNode node;

            lock (Root)
            {
                node = Root;
            }


            lock (node)
            {
                while (node != LinkNode.Empty)
                {
                    if (where.Invoke(node.Value))
                    {
                        lock (node.next)
                        {
                            if(before!=null)
                                before.next = node.next;
                            
                            before = node.next;
                            node = before.next;
                        }
                        affected++;
                    }
                    else
                    {
                        before = node;
                        node = node.next;
                    }
                }
            }
            return affected;
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            Interlocked.Increment(ref enumerators);
            return new Enumerator(this);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            Interlocked.Increment(ref enumerators);
            return new Enumerator(this);
        }
    }
}
14-10-2010 17:26
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
hurricane86
Posting Freak

Messaggi: 1,266
Registrato: Jun 2009
Offline Offline
#2 RE: Parere
0
ma la domanda dove sta? Sorriso

Martino Giovanelli
14-10-2010 18:08
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
Mickey
Coder inside

Messaggi: 950
Registrato: Apr 2009
Offline Offline
#3 RE: Parere
0
Credo voglia sapere se come soluzione vada bene. No?

Michele "Mickey" Marolla
14-10-2010 19:16
Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
TheQult
Subconscio

Messaggi: 129
Registrato: Jul 2010
Offline Offline
#4 RE: Parere
0
Si il senso era quello
Il multithread mi scappare di testa
14-10-2010 19:54
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
miniBill
Posting Freak

Messaggi: 1,700
Registrato: Nov 2008
Offline Offline
#5 RE: Parere
0
non ho capito questo:
Interlocked.Decrement(ref table.enumerators);
non hai già lockato la table? non dovrebbe bastare?
bool System.Collections.IEnumerator.MoveNext()
{
bool ret = false;
lock (this.node.next)
perché locki su .next?
public LinkNode()
{
this.next = this;
???
public void Clear()
{
lock (Root)
{
Root = LinkNode.Empty;
}
lock (Tail)
{
Tail = Root;
}
non conviene mettere il secondo lock dentro il primo, in modo che Root non ti cambi "in mezzo"?
Update e Delete li leggo domani
non ho capito a cosa ti serve refcounters

Nōkírå Zizi
(Questo messaggio è stato modificato l'ultima volta il: 14-10-2010 22:11 da miniBill.)
14-10-2010 22:06
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
Smjert
Senior Member

Messaggi: 424
Registrato: Sep 2009
Offline Offline
#6 RE: Parere
0
MoveNext lo deve lockare perchè se la lista viene usata da due thread, l'if che c'è dopo può risultare Empty anche se in realtà il nodo sta per essere impostato dall'altro thread.

è un modo per inizializzare next anche se sarebbe più corretto inizializzarlo a null (oltretutto essendo una property di una classe in C# vengono autoimpostate al valore di default, in questo caso null).

può stare anche com'è ma non capisco perchè fai Tail = Root, sai già che Root è LinkNode.Empty, ma come l'hai scritto tu Root nel mentre può cambiare e a Tail viene assegnato questo nuovo valore. Lascia così e fai Tail = LinkNode.Empty no?

Passo anch'io l'Update e Delete Look

PS: ma perchè usi tutti quei this? non sono mica necessari anzi..

Stefano Bonicatti.
(Questo messaggio è stato modificato l'ultima volta il: 15-10-2010 0:40 da Smjert.)
15-10-2010 0:39
Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
TheQult
Subconscio

Messaggi: 129
Registrato: Jul 2010
Offline Offline
#7 RE: Parere
0
(14-10-2010 22:06)miniBill ha scritto:  Interlocked.Decrement(ref table.enumerators);
fixed

(14-10-2010 22:06)miniBill ha scritto:  lock (this.node.next)
perché locki su .next?
Per evitare che cambi mentre mi ci sposto ( o no? )

(14-10-2010 22:06)miniBill ha scritto:  this.next = this;
lock(null) esplode

(14-10-2010 22:06)miniBill ha scritto:  lock (Root)
{
Root = LinkNode.Empty;
}
lock (Tail)
{
Tail = Root;
}
fixed

Citazione:non ho capito a cosa ti serve refcounters

Volevo fare delle serializzazioni senza avere enumartoi fra le balle
(15-10-2010 0:39)Smjert ha scritto:  può stare anche com'è ma non capisco perchè fai Tail = Root, sai già che Root è LinkNode.Empty, ma come l'hai scritto tu Root nel mentre può cambiare e a Tail viene assegnato questo nuovo valore. Lascia così e fai Tail = LinkNode.Empty no?
Asd Per scrivere meno

(15-10-2010 0:39)Smjert ha scritto:  PS: ma perchè usi tutti quei this? non sono mica necessari anzi..

if(a!=null)
{
<----- altro thread setta a=null
lock(a)
{
<----------ESPLOSIONE
}
}
PS: grazie
(Questo messaggio è stato modificato l'ultima volta il: 15-10-2010 2:33 da TheQult.)
15-10-2010 2:29
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
TheCrib
Indie Pellerossa

Messaggi: 5,200
Registrato: Sep 2010
Offline Offline
#8 RE: Parere
0
La concurrency e' una questione mooolto delicata e non basta riempire il codice di locks.. anzi, spesso piu' sono le locks, piu' e' probabile che l'implementazione faccia acqua 8)
Il mio consiglio e' quello di trovare piu' di una implementazione gia' fatta.. ma qualcosa che abbia un discorso ed una spiegazione dietro. Perche' sono cose che puo' toppare chiunque.

Non conosco il C# ne precisamente cosa faccia la lock in dettaglio (presumo che estenda un oggetto in modo che abbia una sua lock o "critical section"), ma cose del tipo:
Codice:
lock (this.value)
{
   this.value = value;
}
...sembrano ridondanti. Perche' una semplice assegnazione dovrebbe essere gia' una operazione atomica.. (anche se poi value magari e' un oggetto, presumo che in C#, come per in Java, gli oggetti siano comunque passati per referenza (?))

Altre cose tipo:
Codice:
public void Clear()
{
    lock (Root)
    {
        Root = LinkNode.Empty;
    }
    lock (Tail)
    {
        Tail = Root;
    }
}
..danno un falso senso di sicurezza: ci sono due lock inutili, ma nessuna lock che "atomizzi" le due assegnazioni che andrebbero fatte in un solo colpo.
Credo che in questo caso, quello che dovresti fare e' una singola lock(this).

Secondo me il costrutto lock() e' troppo magico per capire bene come e dove usarlo.
Idealmente uno implementerebbe queste cose a basso livello con una critical section (che e' gia' un concetto di alto livello rispetto all'asm 8).
Una volta messo mano sulle critical sections, quindi con il concetto di creare una risorsa/oggetto fisico di lock, allora le cose diventano piu' chiare.. almeno a me e' servito quello (anche se rimango un beginner con queste cose).

Buon divertimento 8)

Davide Pasca
http://v5.kazzuya.com - @109mae
http://oyatsukai.com - @oyatsukai
"O frechete !" - M.Magnotta
15-10-2010 6:21
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
MonkeySoft
Bloody Monkey

Messaggi: 1,215
Registrato: Dec 2009
Offline Offline
#9 RE: Parere
0
Quoto TheCrib, la lock serve a definire una sezione critica, non a lockare un determinato oggetto... infatti l'ho sempre vista usare un oggetto generico, uno solo per classe.

http://msdn.microsoft.com/it-it/library/...S.80).aspx

Paolo Tajè
Follow me on Twitter
Bloody Monkey | Facebook
15-10-2010 11:56
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
lele85
Senior Member

Messaggi: 396
Registrato: Oct 2010
Online Online
#10 RE: Parere
0
Quando si ha a che fare con la concorrenza i mal di testa sono assicurati. A meno che non si abbia la fortuna di poter lavorare con linguaggi funzionali tipo erlang o haskell. Sorriso

Pensieri Sparsi | Linkedin | My tweets
(Questo messaggio è stato modificato l'ultima volta il: 17-10-2010 23:18 da lele85.)
17-10-2010 21:34
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
miniBill
Posting Freak

Messaggi: 1,700
Registrato: Nov 2008
Offline Offline
#11 RE: Parere
0
(17-10-2010 21:34)lele85 ha scritto:  Quando si ha a che fare con la concorrenza i mal di testa sono assicurati. A meno che non si ha la fortuna di poter lavorare con linguaggi funzionali tipo erlang o haskell. Sorriso
ABBIA
l'accademia della crusca piange Piange

Nōkírå Zizi
17-10-2010 21:50
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
TheCrib
Indie Pellerossa

Messaggi: 5,200
Registrato: Sep 2010
Offline Offline
#12 RE: Parere
0
(17-10-2010 21:34)lele85 ha scritto:  Quando si ha a che fare con la concorrenza i mal di testa sono assicurati. A meno che non si ha la fortuna di poter lavorare con linguaggi funzionali tipo erlang o haskell. Sorriso

Si, ma basta vedere codice erlang o haskell per farsi venire il mal di testa ;)

Davide Pasca
http://v5.kazzuya.com - @109mae
http://oyatsukai.com - @oyatsukai
"O frechete !" - M.Magnotta
17-10-2010 22:59
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
lele85
Senior Member

Messaggi: 396
Registrato: Oct 2010
Online Online
#13 RE: Parere
0
(17-10-2010 21:50)miniBill ha scritto:  ABBIA
l'accademia della crusca piange Piange
Inchino
Che vergogna... caduto su un periodo ipotetico.
Chiedo umilmente scusa. Piange

Pensieri Sparsi | Linkedin | My tweets
17-10-2010 23:15
Visita il sito web di questo utente Trova tutti i messaggi di questo utente Cita questo messaggio nella tua risposta
Rispondi 


Vai al forum: