Programación del sistema Linux 56 variables de condición de subprocesos

Por qué tener variables de condición: para compensar la falta de bloqueos de exclusión mutua

Desventajas de los bloqueos mutex: Los subprocesos solo se pueden ejecutar con bloqueos y bloqueo sin bloqueo (pthread_mutex_lock). Si un subproceso realiza otras operaciones en función de si se produce un cambio en los datos compartidos o no. Luego, si se implementa con un bloqueo mutex, el hilo repetirá las siguientes operaciones:

申请持锁成功
	判断 (共享数据的某个变化是否发生)
		如果有发生,执行其他操作
	如果没发生,解锁,(加sleep()会影响效率)并重新申请持锁
申请持锁失败 阻塞(pthread_mutex_lock) 等待持锁

Si un determinado cambio en los datos compartidos tarda mucho en producirse, el subproceso realizará repetidamente las operaciones anteriores, lo que provocará una pérdida de tiempo de procesamiento de la CPU. Algunas personas dirán que se puede agregar sleep () al pseudocódigo para ahorrar tiempo de procesamiento de la CPU, pero la consecuencia es que no puede garantizar que el proceso pueda encontrar un cierto cambio en los datos compartidos a la velocidad más rápida, lo que afecta la eficiencia. Es decir, en una situación similar, los bloqueos de exclusión mutua tendrán problemas de tiempo y eficiencia.

Entonces, para resolver los problemas de tiempo y eficiencia mencionados anteriormente, se introducen variables de condición

Variables de condición : las variables de
condición permiten que los subprocesos se bloqueen y esperen a que otros subprocesos se envíen señales a sí mismos para despertarlos. Teniendo en cuenta el tiempo de procesamiento de la CPU y la eficiencia, esto compensa la falta de bloqueos de exclusión mutua.


相关 函数 :
pthread_cond_destroy ()
pthread_cond_init ()
pthread_cond_broadcast ()
pthread_cond_signal ()
pthread_cond_timedwait ()
pthread_cond_wait ()

pthread_cond_t 类型,条件变量类型


NAME
       pthread_cond_destroy, pthread_cond_init — destroy and initialize condition variables

SYNOPSIS
       #include <pthread.h>

//销毁
       int pthread_cond_destroy(pthread_cond_t *cond);

//动态初始化条件变量
       int pthread_cond_init(pthread_cond_t *restrict cond,
           const pthread_condattr_t *restrict attr);

//静态初始化条件变量
       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;



NAME
       pthread_cond_broadcast, pthread_cond_signal — broadcast or signal a condition 广播或发出条件的信号

SYNOPSIS
       #include <pthread.h>

       //广播形式的唤醒,唤醒所有因 该条件变量cond而阻塞的线程
       int pthread_cond_broadcast(pthread_cond_t *cond);

       //唤醒 因为该条件变量cond而阻塞的所有线程中的任意一个线程
       int pthread_cond_signal(pthread_cond_t *cond);




NAME
       pthread_cond_timedwait, pthread_cond_wait — wait on a condition

SYNOPSIS
       #include <pthread.h>

//非阻塞等待条件变量变为真,超时等待
       int pthread_cond_timedwait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex,
           const struct timespec *restrict abstime);

//阻塞等待条件变量变为真,参数:条件变量,互斥量
       int pthread_cond_wait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex);

pthread_cond_wait () se usa para bloquear el hilo y montar el hilo en la cola de hilos de bloqueo de la variable de condición cond, luego desbloquearlo y finalmente esperar a que se despierte. Después de ser despertado, se tomará el candado. Si solo hay un hilo de bloqueo, el candado se mantendrá directamente después de ser despertado.

La forma de usar pthread_cond_wait es la siguiente:

1    pthread _mutex_lock(&mutex)

2    while或if(线程执行的条件是否成立)
          pthread_cond_wait(&cond, &mutex);

3    线程执行

4    pthread_mutex_unlock(&mutex);

Pregunta 1: ¿Por qué debemos sujetar el candado primero?

Respuesta : La variable de condición es para compensar la insuficiencia del bloqueo mutex. Ambos deben permitir que solo un subproceso acceda al recurso crítico al mismo tiempo, por lo que se deben agregar bloqueos.

Pregunta 2: ¿Cómo previene pthread_cond_wait () el bloqueo de bloqueo, es decir, si entra en el estado de bloqueo sin desbloquearse, otros subprocesos no podrán acceder a recursos críticos en esta línea?

Respuesta : La implementación interna de pthread_cond_wait () puede entenderse como montar primero el hilo en la cola de bloqueo y luego desbloquearlo. Entonces, dentro de la función, se ha desbloqueado. El momento del desbloqueo interno de la función es muy importante, la función se desbloquea después de montar el hilo en la cola de bloqueo. El propósito de esto es garantizar que otros subprocesos no puedan cambiar el recurso crítico antes de montar el subproceso en la cola de bloqueo. Imagínese lo que sucede si desbloquea primero y luego monta, si después del desbloqueo, otros subprocesos obtienen el bloqueo, cambian el recurso crítico y envían la señal pthread_cond_signal (), hará que este subproceso no responda a este recurso crítico El cambio.

Escenario: El
subproceso mantiene el bloqueo y juzga si la condición está establecida. Si no se establece, pthread_cond_wait () bloquea el subproceso y lo monta en la cola de subprocesos de bloqueo de la variable de condición cond, luego lo desbloquea y finalmente espera despertar. pthread_cond_wait () tomará el bloqueo después de ser despertado. Si solo hay un hilo de bloqueo, retendrá directamente el bloqueo después de ser despertado y comenzará a juzgar si la condición es verdadera. . . . Si está establecido, salte del bucle y continúe con el siguiente paso.

Experimento 1:
Implementado por el método de notificación de variable de condición: los cuatro subprocesos envían continuamente a, b, c, d al terminal en secuencia dentro del tiempo especificado, y cada subproceso genera una letra

Escritura normativa: use variables de condición para realizar el método de notificación

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>

#define THRNUM 4

static int num = 0;

static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;

static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int next(int n)
{
	if(n+1 == THRNUM)
		return 0;
	return n+1;

}

static void *thr_add(void *p)
{
	int n = (int)p;//0 1 2 3
	int c = 'a' + (int)p;
	while(1)
	{
		pthread_mutex_lock(&mut);
		while(num != n)//判断是不是目标下一个线程
			pthread_cond_wait(&cond,&mut);//被唤醒的所有线程抢锁,抢到锁的线程 判断条件是否成立。。。
		write(1,&c,1);
		num = next(num);//准备唤醒下一个线程
		pthread_cond_broadcast(&cond);//惊群
		pthread_mutex_unlock(&mut);
	}
		

	pthread_exit(NULL);
} 

int main()
{
	pthread_t tid[THRNUM];
	int i,err;

	for(i = 0; i < THRNUM; i++)
	{
		err = pthread_create(tid+i,NULL,thr_add,(void *)i);
		if(err)
		{
			fprintf(stderr,"pthread_create(): %s\n",strerror(err));
			exit(1);
		}
	}

	//alarm(5);

	for(i = 0;i < THRNUM; i++)
	{
		pthread_join(tid[i],NULL);
	}

	pthread_mutex_destroy(&mut);
	pthread_cond_destroy(&cond);

	exit(0);
	
}

Supongo que te gusta

Origin blog.csdn.net/LinuxArmbiggod/article/details/114288246
Recomendado
Clasificación