martes, 8 de diciembre de 2015

Hilos con C# (Threads) , ThreadStaticAttribute

Un hilo tiene su propio pila de llamada que almacena todos los métodos que son ejecutados por el hilo. Las variables locales son almacenados en la pila de llamada y son privadas al hilo.

Un hilo también puede tener sus propios datos que no son variables locales. Un campo puede mantener una copia dentro de cada hilo que se tenga, para lo cual se le coloca el atributo ThreadStatic. Como se puede ver en el siguiente ejemplo.

using System;
using System.Threading;

namespace UsandoThreadStaticAttribute
{
    class Program
    {

       //  El valor máximo del campo:  _campo será de 10, si el atributo es
       // retirado el valor alcanza el valor de 20
        [ThreadStatic]
        public static int _campo;

        static void Main(string[] args)
        {
            new Thread(() => 
            {
                for (int i = 0; i < 10; i++)
                {
                    _campo++;
                    Console.WriteLine("Hilo A {0}", _campo);
                }
            }).Start();


            new Thread(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    _campo++;
                    Console.WriteLine("Hilo B {0}", _campo);

                }
            }).Start();

            Console.ReadKey();

        }
    }
}

La imagen presenta la salida.



Hilos con C# (Threads) , detener un hilo.

Para detener la ejecución de un hilo puede usar Thread.Abort. Cuando este método es ejecutado por otro hilo se lanza una excepción, ThreadAbortException. Puede dejar un estado corrupto y hace que la aplicación quede sin poder usarse.

Una mejor forma de detener un hilo es usar una variable compartida tanto para el hilo principal y el subordinado. En el siguiente ejemplo se utiliza un variable compartida. El hilo es inicializado con una expresión lambda (la cual es una expresión corta de un delegado). El hilo se mantiene en ejecución hasta que la variable detener es true. Después que el método Join() es invocado la aplicación espera hasta que el hilo termina de ejecutarse.

using System;
using System.Threading;

namespace DeteniendoHilos
{
    
    class Program
    {
        static void Main(string[] args)
        {
            bool detener = false;

            Thread hilo = new Thread(new ThreadStart(() => 
                {
                    int ni = 0;

                    while (!detener)
                    {
                        Console.WriteLine("Ejecutando ... {0}", ni++);
                        // se detiene por un segundo
                        Thread.Sleep(10000);
                    }
                }));

            hilo.Start();
            Console.WriteLine("Presione cualquier tecla para salir");
            Console.ReadKey();

            detener = true;
            hilo.Join();
            
        }
    }
}


Referencia:
Exam Ref 70-483 Programming in C#


Hilos con C# (Threads) , ParameterizedThreadStart


El constructor de la clase Thread es sobrecargado, y toma una delegado llamado ParameterizedThreadStart. Este puede ser usado si usted quiere pasar algunos datos a través del método start de su hilo para trabajar con el método que usted decida llamar. Como se ve en el siguiente ejemplo.

using System;
using System.Threading;

namespace UsingParameterizedThreadStart
{
    class Program
    {
        public static void MetodoLlamadoPorHilo(object o)
        {
            for (int i = 0; i < (int)o; i++)
            {
                Console.WriteLine("Llamada al metodo MetodoLlamadoPorHilo no: {0}", i);
                Thread.Sleep(0);
            }
        }

        static void Main(string[] args)
        {
            Thread t = new Thread(new ParameterizedThreadStart(MetodoLlamadoPorHilo));
            t.Start(5);
            t.Join();
        }
    }
}

Referencias:
Exam Ref 70-483 Programming in C#

Hilos con C# (Threads) , ejecución en primer y segundo plano

Un elemento importante de entender en la ejecución con hilos es el uso de los conceptos de ejecución en primer y segundo plano. La ejecución en primer plano puede ser usado para mantener viva una aplicación. Solamente cuando todos los hilos en primer plano terminan el CLR (common language runtime) termina con la ejecución de la aplicación. Las ejecuciones en segundo plano son terminados después.

En el siguiente ejemplo se puede observar el uso de estos conceptos.

using System;
using System.Threading;

namespace UsandoHilosBackground
{
    class Program
    {
        public static void MetodoLlamadoPorHilo()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Llamada al metodo MetodoLlamadoPorHilo no: {0}", i);
                Thread.Sleep(0);
            }
        }

        static void Main(string[] args)
        {
            Thread t = new Thread(new ThreadStart(MetodoLlamadoPorHilo));
            // Al ejecutar la aplicación con la propiedad
            // IsBackground = true la aplicación termina de inmediato
            // si la propiedad es true el mensaje del metodo:
            // MetodoLlamadoPorHilo imprime el mensaje.
            t.IsBackground = false;
            t.Start();
        }
    }
}

Referencia:
Exam Ref 70-483 Programming in C#

Hilos con C# (Threads)

Las computadoras actuales manejan varios núcleos y capacidad de ejecución de tareas separadas en su propio proceso, con su propia memoria virtual, como si se tuvieran varios CPU en el equipo. Una forma de aprovechar estos núcleos  y sus procesos es el manejo de hilos. Los hilos son manejados por Windows, quien se asegura de que trabajen de forma organizada.

Cada hilo es autorizado por Windows para ejecutarse durante cierto periodo de tiempo. Después de este tiempo Windows cambia a otro hilo, esto se conoce como context switching.

Esto significa que Windows debe manejar el contexto completo de cada hilo , salvarlo y restaurarlo cada vez que cambia entre hilos. El uso de hilos asegura que cada proceso toma su tiempo sin esperar hasta que otras operaciones terminen, esto mejora lo que en ingles se escribe como responsiveness.

Responsiveness significa que la aplicación sigue accesible al usuario y le permite responder a las acciones que este ejecuta, creando la ilusión de que el CPU puede ejecutar múltiples tareas al mismo tiempo, esto es conocido como paralelismo, es decir, ejecutar múltiples hilos. Windows se asegura que los hilos son distribuidos entre todos los núcleos disponibles, lo que mejora la escalabilidad.

La sobrecarga de trabajo de Windows asociada a la administración de los hilos debe ser tomada en cuenta para determinar el uso de multi-hilos. Si desea manejar escalabilidad y accesibilidad (responsiveness ) en la aplicación,  C# con el NET Framework  le proporciona un conjunto de opciones.

Uso de la clase Thread

El espacio de nombres System.Threading contiene a la clase Thread. Esta clase permite crear los hilos, manejar la prioridad y estatus de estos.

La clase Thread no es algo que deba usarse a la ligera, y solo en caso de necesidades especiales. Al usar la clase Thread tiene control sobre todas las opciones de configuración, como la prioridad para ejecutarse por una gran cantidad de tiempo o configurar opciones avanzadas.

En el siguiente ejemplo se puede observar el uso de la clase Thread para ejecutar un método en otro hilo, aparte del principal. La clase Console sincroniza el uso del flujo de datos (stream) a la salida  (I/O) del equipo desde múltiples hilos. La sincronización es el mecanismo que aseguran que dos hilos no ejecutan una misma parte de su programa al mismo tiempo. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CreandoHilosConThread
{
    class Program
    {

        public static void MetodoLlamadoPorHilo()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Llamada al metodo MetodoLlamadoPorHilo no: {0}", i);
                // vea la nota en Main
                Thread.Sleep(0);
            }
        }

        static void Main(string[] args)
        {
            Thread t = new Thread(new ThreadStart(MetodoLlamadoPorHilo));
            t.Start();

            for (int i = 0; i < 4; i++)
            {
                Console.WriteLine("Hilo principal: ");
                // Thread.Sleep(0) Es usado para señalar a Windows que 
                // el hilo a terminado. En vez de esperar el tiempo 
                // completo asignado por Windows, lo que permite
                // cambiar de inmediato a otro hilo.
                Thread.Sleep(0);
            }

            // El método Join() es llamado y usado por el hilo principal
            // para permitir a éste, esperar hasta que el otro hilo
            // termine.
            t.Join();
        }
    }
}


Referencias:
Exam Ref 70-483 Programming en C#, pag. 5.


martes, 1 de diciembre de 2015

Entity Class en C#

Para crear una Entity Class es necesario hacer uso del espacio de nombres System.Data.Linq.Mapping.

Ejemplo

El atributo Table identifica esta clase como una entity class, el parámetro Name especifica el nombre de la corrrespondiente tabla en la base de datos. Si usted omite el nombre, LINQ para SQL, asume que el nombre de la clase entidad es el mismo que corresponde a la tabla en la base de datos.

El atributo Column describe una columna de la tabla Products que coincide con una propiedad en la clase Product. El atributo Column puede usar varios parámetros. Los que se presentan en el ejemplo, se describen enseguida:


  • IsPrimaryKey especifica que la propiedad es parte de la una llave primaria.
  • DbType especifica el tipo de dato de la columna en la base de datos. En muchos casos LINQ para SQL puede detectar y convertir el dato a su correspondiente tipo en la clase entidad, hay algunas ocaciones en que es necesario especificar en tipo de dato. Por ejemplo, la columna UnitPrice en la tabla Products usa el tipo money de SQL Server. La clase entidad (entity class) especifica el tipo correspondiente de la propiedad como de valor decimal.
  • El parámetro CanBeNull idica si la columna en la base de datos puede contener un valor nulo. El valor por omisión o default para el parámetro CanbeNull es true. Observe que las dos propiedades en la clase Product, correspondientes a las columnas de la tabla en la base de datos, permiten valores nulos (SupplierID y UnitPrice), los cuales son definidos con posibilidad de ser nulos en la clase entidad (entity class).



Ejemplo de la clase:


[Table(Name = "Products")]
public class Product
{
       [Column(IsPrimaryKey = true, CanBeNull = false)]
       public int ProductID { get; set; }

       [Column]
       public int? SupplierID { get; set; }

       [Column(DbType = "money")]
       public decimal? UnitPrice { get; set; }
}


Referencia:
Microsoft Visual C# 2010 Step by Step, página: 550