条件量

条件量

在许多场合中,程序的执行通常需要满足一定的条件,条件不成熟的时候,任务应该进入睡眠阻塞等待,条件成熟时应该可以被快速唤醒。另外,在并发程序中,会其他任务同时访问该条件,因此任何时候都必须以互斥的方式对条件进行访问。条件量就是专门解决上述场景的逻辑机制。

条件和条件量是两个不同的东西,条件是指程序要继续运行所需要的前提条件,比如文件是否读完、内存是否清空等具体的场景限定。而条件量(即pthread_cond_t)要讨论的是一种同步互斥变量,专用于解决上述逻辑场景。

操作流程:在进行条件判断前,先加锁(防止其他任务并发访问),成功加锁后判断条件是否允许,若条件允许,则直接操作临界资源,然后释放锁。若条件不允许,则进入条件量的等待队列中睡眠,并同时释放锁

在条件量中睡眠的任务,可以被其他任务唤醒,唤醒时重新判定条件是否允许程序继续执行,当然也是必须先加锁。

条件量一般要跟互斥锁(或二值信号量)配套使用,互斥锁提供锁住临界资源的功能,条件量提供阻塞睡眠和唤醒的功能。

(1) 初始化条件量

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;

(2) 进入等待状态

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);

(3)唤醒等待任务

int pthread_cond_signal(pthread_cond_t *cond);//唤醒等待任务
int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒所有等待任务

练习

作业:设计一个程序,主线程需要创建2个子线程之后主线程终止,此时进程中有2个子线程A和B,此时进程中有一个临界资源flag,子线程A获取触摸屏坐标并判断坐标值是否在LCD屏的左上角,如果坐标范围满足左上角,则利用条件量和互斥锁来唤醒子线程B,子线程B的任务是判断flag 是否大于0,如果子线程B的条件满足,则让子线程B在终端输出一个字符串即可。要求进程中使用条件量和互斥锁实现线程的同步以及临界资源的互斥访问。


#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/types.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//条件量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
int flag=0;
int ts_x;
int ts_y;

//线程A,获取触摸屏坐标
void * task_A(void * arg)
{
    //0.设置线程的分离属性
    pthread_detach(pthread_self());
    //1.打开触摸屏
    int ts_fd=open("/dev/input/event0",O_RDWR);
    if(ts_fd==-1)
    {
        fprintf(stderr,"open touch screen error,errno:%d%s\n",errno,strerror(errno));
        exit(-1);
    }
    //2.获取触摸屏坐标的值
    struct input_event ts_event;
    int cnt=0;
    while(1)
    {
        cnt =0;
        //获取X轴坐标值
        if(ts_event_type==EV_ABS&&ts_event_code==ABS_X)
        {
            cnt++;
            *ts_x=ts_event_value;
        }
        //获取Y轴坐标值
        if(ts_event_type==EV_ABS&&ts_event_code==ABS_Y)
        {
            cnt++;
            *ts_y=ts_event_value;
        }
        //打印X、Y轴坐标
        if(cnt>=2)
        {
            printf("x= &d\t",*ts_x);
            printf("y= &d\n",*ts_y);
            break;
        }

        //对互斥信号量上锁
        pthread_mutex_lock(&mutex);
        //判断x,y坐标,如果在左上角就唤醒
        if(ts_x<50%%ts_y<50)
        {
            flag=1;
            pthread_cond_signal(&cond);
        }
        //对互斥信号量解锁
        pthread_mutex_unlock(&mutex);
    }
}

//线程B
void * task_A(void * arg)
{
    while(1)
    {
        //对互斥信号量上锁
        pthread_mutex_lock(&mutex);
        //判断flag的值
        if(flag>0)
        {
            pthread_cond_wait(&cond);
        }
        printf("I am thread B\n");
        flag=0;
        //对互斥信号量解锁
        pthread_mutex_unlock(&mutex);
    }
}


int main()
{
    //1.初始化条件量和互斥量
    pthread_cond_init(&cond,NULL);
    pthread_mutex_init(&mutex,NULL);

    //2.创建两个子线程,子线程A和子线程B
    pthread_t thread_A;
    pthread_t thread_B;
    pthread_create(thread_A,NULL,task_A,NULL);
    pthread_create(thread_B,NULL,task_B,NULL);

    //主线程自动退出
    while(1)
    {
        pthread_exit(NULL);
    }
    
    return 0
}
posted @ 2025-04-17 13:45  骗人就变小狗  阅读(273)  评论(0)    收藏  举报