Condição de corrida

Ao invés de fazer artigos longos, vou seguir as sugestões e postar pequenos trechos de código isolados (quem sabe um dia vira artigo). Hoje eu estava aqui pensando sobre programação paralela e fui brincar com o .NET. Segue um exemplo de condição de corrida.

Se eu executo um loop 100.000 vezes por 10 threads diferentes, cada uma incrementando um contador global em um, o que esperamos ao fim da execução é ver o valor de 1 milhão, certo? Só se você implementou corretamente sua aplicação multithreaded, com os devidos mecanismos de sincronização. Execute e compare os resultados.

Em anexo está o projeto (VS2008) para vocês brincarem e não vejo porque não compilar até no framework 1.1. Fazia um tempão que não brincava com threads, então em uma programação rápida, deve ter alguma coisa que melhorar.

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

using System.Diagnostics;

namespace Threading

{

    public class RaceCondition

    {

        int contadorGeral;

        object ElementoSync = new object();

               

        public void ComecaCorrida(Boolean SemControle)

        {

            contadorGeral = 0;

            Thread[] ts = new Thread[10];

            for (int i = 0; i < 10; i++)

            {

                // Cria threads e define qual método o delegate vai chamar, além de dar nome aos bois

                ts[i] = new Thread(SemControle ? new ThreadStart(SemControleIncremento) : new ThreadStart(ComControleIncremento));

                ts[i].Name = "Thread " + i.ToString();

                Console.WriteLine(DumpThread(ts[i]));

            }

           

            foreach (Thread t in ts) t.Start();

            foreach (Thread t in ts) t.Join();

        }

        private string DumpThread(Thread t)

        {

            return "ID Thread: " + t.ManagedThreadId.ToString() + " - " + t.Name;

        }

        private void SemControleIncremento()

        {

            int valorlocal = 0;

            Random rnd = new Random();

            for (int i = 0; i < 100000; i++)

            {

                valorlocal = contadorGeral;

                // Estou usando o spinwait para não causar causar o bloqueio/escalonamento das threads o tempo todo (comportamento do Thread.sleep),

                // então mantenho a thread rodando por x ciclos de CPU. O valor 500 é suficiente para não dar tempo da execução do loop

                // acabar dentro do quantum alocado para a thread corrente.

                Thread.SpinWait(rnd.Next(500));

                //Thread.SpinWait(rnd.Next(50));

                //Thread.Sleep(rnd.Next(5));

                contadorGeral = valorlocal + 1;

            }

            Console.WriteLine(DumpThread(Thread.CurrentThread) + " " + contadorGeral.ToString());

        }

        private void ComControleIncremento()

        {

            int valorlocal = 0;

            Random rnd = new Random();

            // Sincroniza o acesso a esta região de código para evitar condição de corrida.

            lock (ElementoSync)

            {

                for (int i = 0; i < 100000; i++)

                {

                    valorlocal = contadorGeral;

                    Thread.SpinWait(rnd.Next(500));

                    //Thread.SpinWait(rnd.Next(50));

                    //Thread.Sleep(rnd.Next(5));

                    contadorGeral = valorlocal + 1;

                }

            }

            Console.WriteLine(DumpThread(Thread.CurrentThread) + " " + contadorGeral.ToString());

        }

    }

}

        static void Main(string[] args)

        {

            new RaceCondition().ComecaCorrida(true);

            Console.WriteLine();

            new RaceCondition().ComecaCorrida(false);

            Console.ReadLine();

        }

[]s

Luciano Caixeta Moreira

luciano.moreira@microsoft.com

=============================================================

This posting is provided "AS IS" with no warranties, and confers no rights

=============================================================

Threading_20080222.zip