Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 11:22 Der er 10 kommentarer og
1 løsning

Mutual exclusion i C#

Lige et spørgsmål om mutex i C#.

Jeg har brug for at nogle metoder kan eksekveres flere af gangen (Read), mens andre metoder (Write) kun må køres en ad gangen.

Nu er mit spørgsmål så:
Hvis jeg lavet en lock på det object jeg bruger til at læse og skrive når jeg writer, kan jeg så være sikker på at andre tråde er færdige med at læse?

Tråde der reader obtainer jo ikke en lock på objectet, da flere tråde godt kan læse på en gang.
Avatar billede wisen Nybegynder
29. november 2004 - 11:27 #1
Readers/Writers er et klassisk problem inden for datalogi - prøv at kigge på http://www.codeproject.com/threads/mutexrw.asp
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 11:34 #2
Fint eksempel, men leder mere efter en C#/.Net implementation.
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 11:41 #3
Har kigget lidt på .NET Mutex klassen, men kan ikke lige se hvordan det løser mit problem
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 11:49 #4
Man kan ikke locke primitives, men er i++ og i-- thread safe?
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 11:53 #5
Ellers kunne jeg måske boxe en primitive og så tælle den op når en ny reader starter og ned når den er færdig. Men det er jo ikke en hel smuk løsning og vil nok resultere i en masse overhead :/
Avatar billede clausc Nybegynder
29. november 2004 - 12:00 #6
i++ og i-- er ikke tråd-sikre. Man bør bruge metoderneIncrement() og Decrement() på System.Trhreading.Interlocked
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 12:52 #7
Tror i følgende vil virke?
--------------------------
private System.Int32 readers = new System.Int32(0);

private System.Threading.Mutex writeLock = new System.Threading.Mutex();

private BeginMutexRead()
{
    // Make sure we wait until write has finished
    writeLock.WaitOne(writeLock);
    // Make sure nobody else is changing the boxed read conter
    System.Threading.Monitor.Monitor(readers);
    // Add a reader
    readers++;
    if (readers == 1)
    {
        // Require mutex write lock
        writeLock.WaitOne(writeLock);
    }
    System.Threading.Monitor.Exit(readers);
    writeLock.ReleaseMutex(writeLock);
}

private EndMutexRead()
{
    // Make sure we wait until write has finished
    writeLock.WaitOne(writeLock);
    System.Threading.Monitor.Monitor(readers);
    readers--;
    if (readers == 0)
    {
        // Release mutex write lock
        writeLock.ReleaseMutex(writeLock);
    }
    System.Threading.Monitor.Exit(readers);
    writeLock.ReleaseMutex(writeLock);
}

private BeginMutexWrite()
{
    // Make sure we wait until read and write has finished
    writeLock.WaitOne(writeLock);
}

private EndMutexWrite()
{
    // Allow other threads to read and write
    writeLock.ReleaseMutex(writeLock);
}
--------------------------
Avatar billede arne_v Ekspert
29. november 2004 - 13:00 #8
Det her kode (som jeg har porteret fra noget Java kod ejeg havde liggende)
virker ihvertfald:

using System;
using System.Threading;

namespace E1
{
    public class MultiSemaphore {
        public const int EXCLUSIVE = 1;
        public const int SHARED = 2;
        private int nouser;
        private int mode;

        public MultiSemaphore() {
            nouser = 0;
        }

        public void Get(int mode) {
            lock(this)
            {
                while ((this.mode == EXCLUSIVE || mode == EXCLUSIVE) && nouser > 0) {
                    Monitor.Wait(this);
                }
                nouser++;
                this.mode = mode;
            }
        }

        public void Release() {
            lock(this)
            {
                nouser--;
                Monitor.PulseAll(this);
            }
        }
    }

    class MyThread {
        private MultiSemaphore sem;
        private bool excl;

        public MyThread(MultiSemaphore sem, bool excl) {
            this.sem = sem;
            this.excl = excl;
        }

        public void Run() {
            sem.Get(excl ? MultiSemaphore.EXCLUSIVE : MultiSemaphore.SHARED);
            Thread.Sleep(3000);
            sem.Release();
        }
    }
    class MainClass
    {
        private static void Test(bool excl) {
            long start = DateTime.Now.Ticks;
            MultiSemaphore sem = new MultiSemaphore();
            Thread[] t = new Thread[10];
            for (int i = 0; i < t.Length; i++) {
                t[i] = new Thread(new ThreadStart((new MyThread(sem, excl)).Run));
            }
            for (int i = 0; i < t.Length; i++) {
                t[i].Start();
            }
            Thread.Sleep(1000);
            for (int i = 0; i < t.Length; i++) {
                t[i].Join();
            }
            long end = DateTime.Now.Ticks;
            Console.WriteLine((excl ? "Exclusive" : "Shared") + " time = " + (end - start));
        }
        public static void Main(string[] args)
        {
            Test(true);
            Test(false);
        }
    }
}
Avatar billede nemezis_aalborg Nybegynder
29. november 2004 - 20:08 #9
Det ser ud til at virke, men er det ikke noget med at Semaphores kan medføre deadlocks?

Anyway smid et svar ;)
Avatar billede arne_v Ekspert
29. november 2004 - 20:09 #10
svar
Avatar billede arne_v Ekspert
29. november 2004 - 20:12 #11
Ovenstående kan godt lave en deadlock.

tråd 1 laver eksklusiv lock på A
tråd 2 laver eksklusiv lock på B
tråd 1 forsøger at lave eksklusiv lock på B
tråd 2 forsøger at lave eksklusiv lock på A
og så sker der ikke ret meget

Den gængse løsning er at have en konvention om i hvilken rækkefølge locks
skal udtages.

I ovenstående hvis alle tråde skal tage lock på A før de tager på B så kan
der ikke opstå en deadlock.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester