C# ReaderWriterLockSlim

Resumo : neste tutorial, você aprenderá como usar a ReaderWriterLockSlimclasse C# para controlar o acesso a um recurso compartilhado.

Introdução à classe C# ReaderWriterLockSlim

Às vezes, você tem vários threads que leem um recurso compartilhado, mas apenas alguns threads que gravam nele. Nesse caso, o uso da lockinstrução pode diminuir o desempenho do aplicativo.

O motivo é que a lockinstrução pode impedir que vários threads leiam o recurso compartilhado, mesmo que esses threads não precisem de acesso exclusivo.

A ReaderWriterLockSlimclasse permite que vários threads leiam o recurso compartilhado simultaneamente, mas um thread grave nele por vez. Portanto, o ReaderWriterLockSlimpode ajudar a melhorar o desempenho em comparação com a lockafirmação.

O ReaderWriterLockSlimpossui dois tipos de fechaduras:

  • Bloqueio de leitura
  • Bloqueio de gravador

O ReaderWriterLockSlimpermite que vários threads adquiram o bloqueio de leitura ao mesmo tempo, desde que nenhum thread tenha adquirido o bloqueio de gravação.

Além disso, ele permite que apenas um único thread adquira o bloqueio de gravação por vez e impede que outros threads tentem adquirir o bloqueio de leitura ou gravação.

Na prática, ReaderWriterLockSlimé útil para cenários em que seus aplicativos possuem vários leitores e menos gravadores.

Observe que isso ReaderWriterLockSlimincorre em alguma sobrecarga. Portanto, você deve utilizá-lo quando os benefícios do acesso simultâneo forem superiores ao custo de aquisição e liberação do bloqueio.

Exemplo C# ReaderWriterLockSlim

O programa a seguir demonstra como usar o ReaderWriterLockSlimobjeto para controlar o acesso simultâneo a uma variável compartilhada com cinco leitores e dois gravadores:

using static System.Console;

int counter = 0;
ReaderWriterLockSlim _lock = new();

void Read()
{
    while (true)
    {

        try
        {
            _lock.EnterReadLock();
            WriteLine($"R: Thread {Thread.CurrentThread.ManagedThreadId} is reading: {counter}");
        }
        finally
        {
            _lock.ExitReadLock();
        }

        Thread.Sleep(500);
    }
}

void Write()
{
    while (true)
    {
        try
        {
            _lock.EnterWriteLock();
            WriteLine($"W: Thread {Thread.CurrentThread.ManagedThreadId} is writing: {counter++}");
        }
        finally
        {
            _lock.ExitWriteLock();
        }

        Thread.Sleep(2000);
    }
}


// create 5 reader threads
for (int i = 0; i < 5; i++)
{
    new Thread(() => Read()).Start();
}

// create 2 writer threads
for (int i = 0; i < 2; i++)
{
    new Thread(() => Write()).Start();
}Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, declare uma variável inteira counter:

int counter = 0;Linguagem de código:  C#  ( cs )

Segundo, crie um novo ReaderWriterLockSlimobjeto chamado _lock:

ReaderWriterLockSlim _lock = new();Linguagem de código:  C#  ( cs )

Terceiro, defina o Reader()método que adquire um bloqueio de leitura no _lockobjeto chamando o EnterReadLock()método no trybloco:

void Read()
{
    while (true)
    {

        try
        {
            _lock.EnterReadLock();
            WriteLine($"R: Thread {Thread.CurrentThread.ManagedThreadId} is reading: {counter}");
        }
        finally
        {
            _lock.ExitReadLock();
        }

        Thread.Sleep(500);
    }
}Linguagem de código:  C#  ( cs )

O Read()método exibe o valor da countervariável.

Além disso, ele libera o bloqueio de leitura do _lockobjeto no finallybloco chamando o ExitReadLock()método.

O Read()método atrasa 500 milissegundos, o que equivale a meio segundo.

Quarto, defina o Writemétodo que aumenta a variável compartilhada counter:

void Write()
{
    while (true)
    {
        try
        {
            _lock.EnterWriteLock();
            WriteLine($"W: Thread {Thread.CurrentThread.ManagedThreadId} is writing: {counter++}");
        }
        finally
        {
            _lock.ExitWriteLock();
        }

        Thread.Sleep(2000);
    }
}Linguagem de código:  C#  ( cs )

O Writemétodo adquire um bloqueio de gravação no _lockobjeto do trybloco chamando o EnterWriteLock()método.

Depois disso, aumenta em counterum e exibe o countervalor no console. O Writemétodo libera o bloqueio de gravação no finallybloco chamando o ExitWriteLock()método.

O Writemétodo tem um atraso de 2.000 milissegundos, ou seja, 2 segundos.

Quinto, crie dois threads de leitura e dois threads de gravação. Os threads leitores executam o Readmétodo enquanto os threads gravadores executam o Writemétodo.

// create 5 reader threads
for (int i = 0; i < 5; i++)
{
    new Thread(() => Read()).Start();
}

// create 2 writer threads
for (int i = 0; i < 2; i++)
{
    new Thread(() => Write()).Start();
}Linguagem de código:  C#  ( cs )

Aqui está um exemplo de saída do programa:

R: Thread 9 is reading: 0
R: Thread 8 is reading: 0
R: Thread 10 is reading: 0
R: Thread 11 is reading: 0
W: Thread 13 is writing: 0
W: Thread 12 is writing: 1
R: Thread 7 is reading: 2
R: Thread 10 is reading: 2
R: Thread 11 is reading: 2
R: Thread 7 is reading: 2
R: Thread 9 is reading: 2
R: Thread 8 is reading: 2
R: Thread 7 is reading: 2
R: Thread 11 is reading: 2
R: Thread 8 is reading: 2
R: Thread 9 is reading: 2
R: Thread 10 is reading: 2
R: Thread 9 is reading: 2
R: Thread 8 is reading: 2
R: Thread 11 is reading: 2
R: Thread 10 is reading: 2
R: Thread 7 is reading: 2
W: Thread 13 is writing: 2
W: Thread 12 is writing: 3
R: Thread 8 is reading: 4
R: Thread 9 is reading: 4
R: Thread 9 is reading: 4
R: Thread 10 is reading: 4
R: Thread 7 is reading: 4
R: Thread 11 is reading: 4
R: Thread 8 is reading: 4
R: Thread 8 is reading: 4
R: Thread 11 is reading: 4
R: Thread 7 is reading: 4
R: Thread 10 is reading: 4
R: Thread 9 is reading: 4
...Linguagem de código:  C#  ( cs )

Para encerrar o programa, você precisa fechá-lo.

Resumo

  • Use C# ReaderWriterLockSlimpara permitir que vários threads leiam o recurso compartilhado simultaneamente, mas um thread grave nele por vez.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *