Lectura del código fuente de libco (1): Hello World

1. ¿Qué es una corrutina?

   1.1 Proceso

   1.2 Hilo

   1.3 Corutina

2 、 libco 库 跑 hola mundo


1. ¿Qué es una corrutina?

    Antes de comprender la corrutina, debe comparar las diferencias entre procesos, subprocesos y corrutinas:

        

1.1 Proceso

    Un proceso puede entenderse como la unidad básica de asignación de recursos. El sistema operativo utiliza un proceso como la unidad básica para asignar los recursos del sistema, incluidos los recursos de memoria y los recursos del intervalo de tiempo de la CPU. El conmutador de procesos es el sistema operativo, y el tiempo de conmutación se basa en la propia estrategia de conmutación del sistema operativo, y el usuario no lo sabe. El contenido de conmutación del proceso incluye el directorio global de la página, la pila del núcleo y el contexto del hardware. El contenido de conmutación se almacena en la memoria. El proceso de cambio de proceso es de "modo de usuario a modo de kernel a modo de usuario", y la eficiencia de cambio es baja. Un proceso tiene su propio espacio de direcciones independiente, que incluye:

  • Segmento de datos
  • Fragmento de código
  • montón
  • Apilar
  • expediente

  Un proceso puede contener varios subprocesos.

1.2 Hilo

    El subproceso es la unidad básica de programación de la CPU. El cambio entre subprocesos debe pasar del modo de usuario al modo de kernel, que es programado por la CPU. El conmutador de subprocesos es el sistema operativo, y el tiempo de conmutación se basa en la propia estrategia de conmutación del sistema operativo, y el usuario no tiene percepción. El contenido de conmutación del hilo incluye la pila del núcleo y el contexto del hardware. El contenido del cambio de hilo se almacena en la pila del kernel. El proceso de cambio de hilo es de "modo de usuario a modo de kernel a modo de usuario", y la eficiencia de cambio es moderada. Todos los subprocesos de un proceso comparten los recursos del proceso, pero los subprocesos también tienen sus propios recursos independientes. Estos recursos son:

  • ID de subproceso : cada subproceso tiene su propio ID de subproceso, que es único en este proceso. El proceso usa esto para identificar el hilo.
  • El valor del grupo de registros: debido a que los subprocesos se ejecutan al mismo tiempo, cada subproceso tiene sus propias pistas de ejecución diferentes. Cuando se cambia de un subproceso a otro, el estado del conjunto de registros del subproceso original debe guardarse para el futuro. cambiado de nuevo a.
  • Pila de subprocesos : la pila es necesaria para garantizar que los subprocesos se ejecuten de forma independiente. Una función de subproceso puede llamar a una función, y la función llamada se puede anidar capa por capa, por lo que el subproceso debe tener su propia pila de funciones para que la llamada a la función se pueda ejecutar normalmente sin verse afectada por otros subprocesos.
  • Código de retorno de error : debido a que hay muchos subprocesos ejecutándose al mismo tiempo en el mismo proceso, es posible que un subproceso haya establecido el valor errno después de realizar una llamada al sistema, y ​​el subproceso aún no haya procesado el error, y otro subproceso está siendo programado por el planificador en este momento Ponlo en funcionamiento, de modo que se pueda modificar el valor incorrecto. Por lo tanto, los diferentes subprocesos deben tener sus propias variables de código de retorno de error.
  • Código de enmascaramiento de señal del hilo : dado que cada hilo está interesado en señales diferentes, el código de enmascaramiento de señal del hilo debe ser administrado por el propio hilo. Pero todos los subprocesos comparten el mismo controlador de señales.
  • Prioridad del hilo : Dado que el hilo debe poder programarse como un proceso, debe haber un parámetro disponible para la programación. Este parámetro es la prioridad del hilo.

1.3 Corutina

   Una corrutina puede entenderse como un subproceso en modo de usuario, es decir, un subproceso puede contener múltiples corrutinas, que son creadas por el usuario y controladas por el usuario para programar la corrutina. El conmutador de la corrutina es el usuario (programador o aplicación), y el tiempo de conmutación lo determina el propio programa del usuario. El contenido de conmutación de la corrutina es el contexto de hardware, y la memoria de conmutación se almacena en la propia variable del usuario (pila o montón de usuarios). El proceso de conmutación de la corrutina solo tiene el modo de usuario, es decir, no cae en el modo kernel, por lo que la eficiencia de conmutación es alta. Aunque se pueden cambiar múltiples goroutines en un hilo, múltiples goroutines se ejecutan en serie y solo se pueden ejecutar en un hilo, y no pueden aprovechar las capacidades de múltiples núcleos de la CPU. La corrutina en el hilo no es perceptible para la CPU, y la CPU solo percibe que se está ejecutando un hilo. Los principales recursos que posee la corrutina son:

  • El contexto de la corrutina, es decir, el valor de varios registros
  • La pila propiedad de la corrutina

2 、 libco 库 跑 hola mundo

    Libco es una biblioteca de corrutinas C / C ++ que se utiliza a gran escala en el backend de WeChat. Se ha estado ejecutando de manera estable en decenas de miles de máquinas en el backend de WeChat desde 2013. Libco puede admitir escritura síncrona o asíncrona a través de solo unas pocas interfaces de función co_create / co_resume / co_yield y co_poll, tan fácil como una biblioteca de subprocesos. Al mismo tiempo, la biblioteca proporciona enlaces para las funciones de la familia de sockets, de modo que los servicios lógicos de back-end se pueden transformar de forma asincrónica casi sin modificar el código lógico.

    Dirección de Github: https://github.com/Tencent/libco .

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include "co_routine.h"
using namespace std;
struct stTask_t
{
	int id;
};
struct stEnv_t
{
	stCoCond_t* cond;
	queue<stTask_t*> task_queue;
};
void* Producer(void* args)
{
	co_enable_hook_sys();
	stEnv_t* env=  (stEnv_t*)args;
	int id = 0;
	while (true)
	{
		stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t));
		task->id = id++;
		env->task_queue.push(task);
		printf("%s:%d produce task %d\n", __func__, __LINE__, task->id);
		co_cond_signal(env->cond);
		poll(NULL, 0, 1000);
	}
	return NULL;
}
void* Consumer(void* args)
{
	co_enable_hook_sys();
	stEnv_t* env = (stEnv_t*)args;
	while (true)
	{
		if (env->task_queue.empty())
		{
			co_cond_timedwait(env->cond, -1);
			continue;
		}
		stTask_t* task = env->task_queue.front();
		env->task_queue.pop();
		printf("%s:%d consume task %d\n", __func__, __LINE__, task->id);
		free(task);
	}
	return NULL;
}

int main()
{
	stEnv_t* env = new stEnv_t;
	env->cond = co_cond_alloc();

	stCoRoutine_t* consumer_routine;
	co_create(&consumer_routine, NULL, Consumer, env);
	co_resume(consumer_routine);

	stCoRoutine_t* producer_routine;
	co_create(&producer_routine, NULL, Producer, env);
	co_resume(producer_routine);
	
	co_eventloop(co_get_epoll_ct(), NULL, NULL);
	return 0;
}

     Este es un ejemplo de productor-consumidor. En este ejemplo, hay principalmente dos funciones:

  • Función de productor: el productor es responsable de colocar las tareas en la cola de tareas.
  • Función de consumidor: el consumidor es responsable de tomar las tareas de la cola de tareas para su ejecución.

   En la función principal, se crean dos corrutinas para que se ejecuten estas dos funciones. Las dos interfaces de libco se utilizan principalmente aquí, a saber, co_create () y co_resume () . Co_create () es responsable de crear una corrutina, y co_resume () Responsable para iniciar una corrutina. Aquí, la creación de una corrutina es muy diferente de la creación de un hilo. El hilo se puede ejecutar directamente cuando se crea, pero la corrutina no se ejecuta después de que se crea, pero necesita llamar a otra función para ejecutarse.

 

Supongo que te gusta

Origin blog.csdn.net/MOU_IT/article/details/114649736
Recomendado
Clasificación