系统编程
POSIX信号量
题目
设计一个程序,主线程需要创建2个子线程之后主线程终止,此时进程中有2个子线程A和B,此时进程中有一个临界资源flag,子线程A获取触摸屏坐标并判断坐标值是否在LCD屏的左上角,如果坐标范围满足左上角,则利用条件量和互斥锁来唤醒子线程B,子线程B的任务是判断flag 是否大于0,如果子线程B的条件满足,则让子线程B在终端输出一个字符串即可。要求进程中使用条件量和互斥锁实现线程的同步以及临界资源的互斥访问。
代码
/***********************************************************************************
*
* file name: pthread_cond.c
* author : [email protected]
* date : 2024/05/31
* function : 该案例是在进程中使用条件量和互斥锁实现线程的同步以及临界资源的互斥访问
* note :
* 由于使用了线程函数接口,所以编译时需要加上-pthread
* version :
*
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*
* **********************************************************************************/
/************************************头文件*****************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <pthread.h>
#include <unistd.h>
/***********************************************************************************/
/************************************全局变量***************************************/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int lcd_fd; //lcd屏文件
int ts_fd; //触摸屏文件
int *lcd_mp; //指向LCD屏映射空间地址的指针变量
// 临界资源flag,应该使用volatile修饰,防止编译器优化
volatile int x,y;
volatile int flag = 0;
/**********************************************************************************/
/***********************************************************************************
*
* name : thread_A_func
* function : 线程A的任务函数,获取触摸屏坐标并判断坐标值是否在LCD屏的左上角,
* 如果坐标范围满足左上角,则利用条件量和互斥锁来唤醒子线程B
* param :
* none
*
* retval : none
* author : [email protected]
* date : 2024/05/31
* note : 由于线程B处于挂起状态,所以需要在线程A中设定条件唤醒线程B进,防止
* 死锁情况出现
* version :
*
* *********************************************************************************/
void *thread_A_func(void *arg)
{
//2.读取输入设备的信息
struct input_event ts_event;
int cnt = 0;
while(1)
{
read(ts_fd,&ts_event,sizeof(ts_event));
//3.分析读取的设备信息 (type + code + value)
if (ts_event.type == EV_ABS) //说明是触摸屏
{
if (ts_event.code == ABS_X) //说明是X轴
{
cnt++;
x = ts_event.value * 800 / 1024;
}
if (ts_event.code == ABS_Y) //说明是Y轴
{
cnt++;
y = ts_event.value * 480 / 600;
}
if(cnt >= 2)
{
cnt = 0;
printf("x = %d, y = %d\n",x,y);
// 用互斥锁上锁
pthread_mutex_lock(&mutex);
//判断坐标值是否在LCD屏左上角
if (x >= 0 && x <= 200 && y >= 0 && y <= 200)
{
flag = 1;
//用条件来唤醒子线程B
pthread_cond_signal(&cond);
}
// 用互斥锁解锁
pthread_mutex_unlock(&mutex);
}
}
}
}
/***********************************************************************************
*
* name : thread_B_func
* function : 线程B的任务函数,判断fag 是否大于 0,如果子线程B的条件满足,
* 则让子线程B在终端输出字符串
* param :
* none
*
* retval : none
* author : [email protected]
* date : 2024/05/31
* note : 由于经过线程A的信号通知,flag 变为1,所以线程B的条件满足,执行线程B的
* 任务函数后,需对flag的值进行修改,防止死锁情况出现
* version :
*
* *********************************************************************************/
void *thread_B_func(void *arg)
{
while (1)
{
// 用互斥锁上锁
pthread_mutex_lock(&mutex);
// 判断flag是否大于0
if (flag <= 0)
{
pthread_cond_wait(&cond, &mutex);
}
printf("The coordinates are in the upper left corner\n");
flag = 0;
// 用互斥锁解锁
pthread_mutex_unlock(&mutex);
}
}
int main()
{
//打开LCD屏
lcd_fd = open("/dev/fb0",O_RDWR);
//打开触摸屏
ts_fd = open("/dev/input/event0",O_RDWR);
//2.对LCD进行内存映射 mmap
lcd_mp = (int *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);
// 初始化读写锁
// pthread_rwlock_init(&rwlock, NULL);
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
// 初始化条件变量
pthread_cond_init(&cond, NULL);
// 创建子线程B
pthread_t thread_B;
pthread_create(&thread_B, NULL, thread_B_func, NULL);
// 创建子线程C
pthread_t thread_A;
pthread_create(&thread_A, NULL, thread_A_func, NULL);
// 把子线程AB设置为分离态
pthread_detach(thread_B);
pthread_detach(thread_A);
// 主线程终止
pthread_exit(NULL);
return 0;
}