目錄題目解析代碼結果展示 題目 解析 該題主要依靠條件量和互斥鎖來實現線程之間的同步與互斥,分析主線程、線程A和線程B的任務如下: 主線程: 打開LCD屏和觸摸屏的硬體文件,並分別存儲兩個文件的文件描述符,方便後面進行條件判斷。 開啟線程A和線程B。 定義並初始化條件量和互斥量,方便後續線程內進 ...
目錄
題目
解析
該題主要依靠條件量和互斥鎖來實現線程之間的同步與互斥,分析主線程、線程A和線程B的任務如下:
主線程:
- 打開LCD屏和觸摸屏的硬體文件,並分別存儲兩個文件的文件描述符,方便後面進行條件判斷。
- 開啟線程A和線程B。
- 定義並初始化條件量和互斥量,方便後續線程內進行上鎖和掛起步驟
線程A:
- 讀取觸摸屏坐標,並對讀取到的坐標值進行判斷。
- 坐標條件判斷滿足後,利用pthread_cond_signal()函數介面對線程B中掛起的條件量進行喚醒操作。
線程B:
- 當flag條件不滿足時,進入掛起狀態,等待線程A的喚醒,再次對flag條件進行判斷。
- 當flag條件滿足且自身處於喚醒狀態時,輸出相應的字元串到終端。
代碼
/********************************************************************************
*
* file name: demo.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>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
/****************************全局變數*********************************************/
volatile int flag; //臨界資源,用於條件判斷是否滿足輸出字元串
int *lcd_mp; //指向LCD屏映射空間地址的指針變數
int ts_fd; //觸摸屏文件
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER; //定義一個互斥量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //定義一個條件量
// #define DEBUG //調試代碼用,開啟後可看到觸摸坐標
/********************************************************************************
*
* name : thread_A_task
* function : 線程A的任務函數,實現對觸摸屏坐標的判斷以及條件喚醒線程B
* param :
* none
*
* retval : none
* author : [email protected]
* date : 2024/05/31
* note : 由於線程B處於掛起狀態,所以一定要線上程A中設定條件對線程B進行喚醒,防止
* 死鎖情況出現
* version :
*
* *****************************************************************************/
void *thread_A_task(void *arg)
{
//定義觸摸屏參數變數
struct input_event ts_event;
//定義一個變數,用於判斷坐標是否讀取完整
int cnt = 0;
//定義兩個變數,分別存觸摸屏橫坐標與縱坐標
int x = -1, y = -1;
//迴圈判斷觸摸屏坐標是否滿足“處於左上角”條件
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;
#ifdef DEBUG
//調試代碼用
printf("x = %d y = %d\n",x,y);
#endif
//上鎖
pthread_mutex_lock(&fastmutex);
//條件判斷
if(x >= 0 && x <= 200 && y >= 0 && y <= 200 )
{
//清空獲取坐標
x = -1;
y = -1;
//將標誌量置為一
flag = 1;
// 條件滿足時喚醒線程B
pthread_cond_signal(&cond);
}
// 解鎖
pthread_mutex_unlock(&fastmutex);
}
}
}
/********************************************************************************
*
* name : thread_B_task
* function : 線程B的任務函數,在flag小於0時掛起,等待線程A的喚醒;在喚醒狀態下且條件
* 滿足時,在終端輸出一串字元串
* param :
* none
*
* retval : none
* author : [email protected]
* date : 2024/05/31
* note : 由於線程B處於掛起狀態,所以一定要線上程A中設定條件對線程B進行喚醒,防止
* 死鎖情況出現
* version :
*
* *****************************************************************************/
void *thread_B_task(void *arg)
{
//迴圈判斷輸出字元串條件是否滿足
while(1)
{
//上鎖
pthread_mutex_lock(&fastmutex);
while(!flag)
{
pthread_cond_wait(&cond, &fastmutex);
}
printf("Touch coordinates in the upper left corner~\n");
flag = 0;
// 解鎖
pthread_mutex_unlock(&fastmutex);
}
}
int main(int argc,const char *argv[])
{
/****條件準備****/
// 打開LCD
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
fprintf(stderr, "open error, errno : %d, %s\n", errno, strerror(errno));
exit(1);
}
// 對LCD進行記憶體映射 mmap
lcd_mp = (int *)mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if(lcd_mp == MAP_FAILED)
{
fprintf(stderr, "mmap error, errno : %d, %s\n", errno, strerror(errno));
exit(2);
}
// 打開觸摸屏
ts_fd = open("/dev/input/event0", O_RDWR);
if(ts_fd == -1)
{
fprintf(stderr, "open error, errno : %d, %s\n", errno, strerror(errno));
exit(3);
}
//初始化一個互斥鎖
pthread_mutex_init(&fastmutex, NULL);
//初始化一個條件量
pthread_cond_init(&cond, NULL);
//創建兩個線程:線程A和線程B
pthread_t thread_A;
pthread_t thread_B;
pthread_create(&thread_A, NULL, thread_A_task, NULL);
pthread_create(&thread_B, NULL, thread_B_task, NULL);
//將線程A設定為分離模式
pthread_detach(thread_A);
pthread_detach(thread_B);
//關閉主線程
pthread_exit(NULL);
}