with thread start parametros parameterizedthreadstart method hilos example con c# multithreading delegates type-inference

c# - thread - Hilos y delegados-No entiendo completamente sus relaciones



thread c# example (2)

El multihilo es muy complejo. Está cortando y pegando código sin siquiera aprender nada sobre los aspectos más básicos de los hilos: cómo iniciar un hilo. Pegar algo de la web en una interfaz de usuario para arreglar o modificar un control, es una cosa. Este es un tipo de proceso completamente diferente. Necesita estudiar el tema, escribir todo su propio código y entender exactamente cómo funciona, de lo contrario, simplemente está perdiendo el tiempo con esto.

Un delegado es la versión .NET de un puntero de función de tipo seguro. Todos los hilos requieren un punto de entrada para iniciar la ejecución. Por definición, cuando se crea un subproceso primario, siempre ejecuta Main () como punto de entrada. Cualquier subproceso adicional que cree necesitará un punto de entrada definido explícitamente, un puntero a la función en la que deberían comenzar la ejecución. Así que los hilos siempre requieren un delegado.

Los delegados a menudo también se usan en subprocesos para otros propósitos, principalmente devoluciones de llamadas. Si desea que un subproceso informe algo de información, como el estado de finalización, una posibilidad es crear una función de devolución de llamada que el subproceso pueda usar. De nuevo, el hilo necesita un puntero para poder ejecutar la devolución de llamada, por lo que los delegados también se utilizan para esto. A diferencia de un punto de entrada, estos son opcionales, pero el concepto es el mismo.

La relación entre los subprocesos y los delegados es que los subprocesos secundarios no pueden simplemente llamar a métodos como el subproceso de la aplicación principal, por lo que se necesita un puntero de función en su lugar y los delegados actúan como punteros de función.

No ve al delegado y no creó uno porque el marco lo está haciendo por usted en el constructor de subprocesos. Puede pasar el método que desea usar para iniciar el hilo, y el código del marco crea un delegado que apunta a este método para usted. Si quisiera usar una devolución de llamada, tendría que crear un delegado usted mismo.

Aquí está el código sin expresiones lambda. SomeClass tiene algún procesamiento que lleva mucho tiempo y se realiza en subprocesos en segundo plano. Para ayudar con esto, se ha creado SomeThreadTask, que contiene el código de proceso y todo lo que el hilo necesita para ejecutarlo. Un segundo delegado se utiliza para una devolución de llamada cuando se realiza el hilo.

El código real sería más complicado, y una clase real nunca debería tener que saber cómo crear subprocesos, etc. para tener objetos de administrador.

// Create a delegate for our callback function. public delegate void SomeThreadTaskCompleted(string taskId, bool isError); public class SomeClass { private void DoBackgroundWork() { // Create a ThreadTask object. SomeThreadTask threadTask = new SomeThreadTask(); // Create a task id. Quick and dirty here to keep it simple. // Read about threading and task identifiers to learn // various ways people commonly do this for production code. threadTask.TaskId = "MyTask" + DateTime.Now.Ticks.ToString(); // Set the thread up with a callback function pointer. threadTask.CompletedCallback = new SomeThreadTaskCompleted(SomeThreadTaskCompletedCallback); // Create a thread. We only need to specify the entry point function. // Framework creates the actual delegate for thread with this entry point. Thread thread = new Thread(threadTask.ExecuteThreadTask); // Do something with our thread and threadTask object instances just created // so we could cancel the thread etc. Can be as simple as stick ''em in a bag // or may need a complex manager, just depends. // GO! thread.Start(); // Go do something else. When task finishes we will get a callback. } /// <summary> /// Method that receives callbacks from threads upon completion. /// </summary> /// <param name="taskId"></param> /// <param name="isError"></param> public void SomeThreadTaskCompletedCallback(string taskId, bool isError) { // Do post background work here. // Cleanup the thread and task object references, etc. } } /// <summary> /// ThreadTask defines the work a thread needs to do and also provides any data /// required along with callback pointers etc. /// Populate a new ThreadTask instance with any data the thread needs /// then start the thread to execute the task. /// </summary> internal class SomeThreadTask { private string _taskId; private SomeThreadTaskCompleted _completedCallback; /// <summary> /// Get. Set simple identifier that allows main thread to identify this task. /// </summary> internal string TaskId { get { return _taskId; } set { _taskId = value; } } /// <summary> /// Get, Set instance of a delegate used to notify the main thread when done. /// </summary> internal SomeThreadTaskCompleted CompletedCallback { get { return _completedCallback; } set { _completedCallback = value; } } /// <summary> /// Thread entry point function. /// </summary> internal void ExecuteThreadTask() { // Often a good idea to tell the main thread if there was an error bool isError = false; // Thread begins execution here. // You would start some kind of long task here // such as image processing, file parsing, complex query, etc. // Thread execution eventually returns to this function when complete. // Execute callback to tell main thread this task is done. _completedCallback.Invoke(_taskId, isError); } } }

Escribí un código que se parece a esto:

Thread t = new Thread(() => createSomething(dt, start, finish) ); t.Start();

Y funciona (a veces parece que hay varios hilos).

Sin embargo, no uso ningún delegado.

  1. ¿Cuál es el significado de una banda de rodadura sin un delegado?
  2. Si es necesario un delegado, entonces dígame qué y cómo se hace la conexión con el delegado.

Está utilizando un delegado, esto es solo azúcar sintáctica C # para:

Thread t = new Thread(new ThreadStart( () => createSomething(dt, start, finish))); t.Start();

El compilador está inferiendo de la expresión lambda y las diferentes sobrecargas que tiene el constructor Thread , que su intención es:

  • Crear una instancia del delegado ThreadStart .
  • Paselo como un argumento a la sobrecarga del constructor de Thread que acepta un objeto ThreadStart .

También podría escribir esto de manera equivalente con la sintaxis anónima-delegada:

Thread t = new Thread(delegate() { createSomething(dt, start, finish); } ); t.Start();

Si los argumentos para createSomething no son locales (capturados), puede escribir esto sin métodos anónimos en conjunto, lo que debería resaltar la creación del delegado de manera mucho más clara:

private void Create() { createSomething(dt, start, finish))); } ... Thread t = new Thread(new ThreadStart(Create)); //new ThreadStart is optional for the same reason t.Start();