版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、精选优质文档-倾情为你奉上嵌入式实验报告学院: xxx 班级: xxx 学号: xxx 姓名: xxx 成员: xxx 一、 基础知识部分1. 多线程实验本章主要讲解线程的概念和线程间的同步方式。实验一主要介绍线程的概念和线程的创建,实验二、实验三、实验四分别介绍了信号量、互斥锁、条件变量的作用和使用。1.1 线程的介绍线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的
2、工作,称为多线程。线程是允许应用程序并发执行多个任务的一种机制,是程序运行后的任务处理单元,也是SylixOS操作系统任务调度的最小单元。在多核CPU中,同时可以有多个线程在执行,实现真正意义上的并行处理。线程入口函数是一个能够完成特定任务的函数,因此线程入口函数的编写上与普通函数没有太多区别。线程的创建函数如下: l 创建线程失败,函数返回非0的错误代码,成功返回0;l *thread pthread_t类型的缓冲区,保存一个线程的线程ID;l *attr 设置线程属性,设置为NULL标识创建的新线程使用默认属性;l *(*start_routine) 线程入口函数函数名 l *arg向所创
3、建线程传入的参数1.2 信号量的概念信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。信号量是一个在进程和线程中都可以使用的同步机制。信号量类似于一个通知,某个线程发出一个通知,等待此通知的线程收到通知后,会执行预先设置的工作。当接收通知的线程没有收到通知前,会处于阻塞状态。信号量可以连续发送多次,处理线程同样也会处理多次。信号量实质是一个计数器,信号量发送
4、一次,计数值增加1,信号量每获取一次,计数值就减1,当计数值为0时,等待信号量线程阻塞。等待信号量过程中,还可以设置等待时间,超过设定时间,等待信号量的线程就不会继续等待,而是继续执行后续任务。1.3 互斥锁在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。互斥锁是避免在同一时间共享资源被多个线程同时访问。互斥锁在使用时类似一把锁,在访问共享资源前对其上锁,在访问完成后,将此资源解锁以便其他线程可以访问。任何试图访问已经被上锁资源的的线程都会被阻塞,直至访问的资
5、源被解锁。如果该资源解锁时有多个试图访问资源的线程被阻塞,那么只有一个线程会被唤醒访问共享资源,SylixOS唤醒原则采用基于优先级的判断,优先级高的优先被唤醒。1.4 条件变量条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。互斥锁能够解决多线程中访问资源冲突的问题,其状态非常简单,只有上锁和解锁两种状态。当线程之间有其他需要同步的条件时,使用互斥锁会十分不方便。比如将线程设置为等待某一个
6、条件满足后开始工作,这个时候使用互斥锁,只能频繁的查询该状态,这样会宝贵的CPU资源。这时使用条件变量是一个更合适的解决方案。条件变量能够给多个线程提供一个会合的场所,条件变量与互斥锁一起使用,允许线程以无竞争的方式等待特定的条件发生。条件变量本身需要使用互斥锁保护,在改变条件变量之前需要使用互斥锁对其上锁。1.5信号量与互斥锁的区别信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。当信号量为单值信号量时,也可以完成一个资源的互斥访问。互斥锁(又名互斥量)强调的是资源的访问互斥:互斥锁是用在多线程多任
7、务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的” 也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进行操作。在有些情况下两者可以互换。 条件变量常与互斥锁同时使用,达到线程同步的目的:条
8、件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。在发送信号时,如果没有线程等待在该条件变量上,那么信号将丢失;而信号量有计数值,每次信号量post操作都会被记录。2. 多进程实验本章主要讲述进程相关概念、进程的创建、退出和进程间的通信。针对进程的创建和进程间通信设计了3组实验,实验一主要讲述进程的创建,实验二和实验三讲述了进程间通信常用的2种方式。2.1 进程的介绍进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的
9、计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程是一个可执行程序的实例。一个编译后的可执行程序在操作系统中运行后,就成为了一个进程,如果执行了两次,就创造了两个进程。从资源管理的角度看,一个进程会独占一些资源,如地址空间、程序代码、文件描述符表和程序运行的其他必要数据集合。其他进程中的函数无法访问此进程的资源,同样此进程的函数也无法访问其他进程中的资源。比如进程1打开了串口1,那么进程2就无法使用进程1打开的串口文件描述符向串口1收发数据。进程在操作系统中使用进程号(进程ID)表示,进程ID是一个非负整数,用以唯一标识系统中的某个进程。2.2 进程的创
10、建进程管理主要是指进程的创建和退出。在Linux/Unix中,进程的创建往往通过fork函数和exec函数配合使用来完成,fork函数从一个进程(父进程)复制出一个新的进程(子进程),随后子进程调用exec函数装载一个新的可执行文件替换当前进程代码,从而实现一个进程启动另外一个进程。2.3 进程间通信2.2.1 共享内存共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同
11、的处理器可能用到不同的数据。共享内存是允许两个或多个进程读写一个共享的物理存储区域。因为数据不需要在进程间进行复制,因此共享内存是速度最快的进程间通信方式。但共享内存本身也存在一些不足,由于共享内存的数据会被两个或多个进程操作,如果两个进程同时向共享内存写入数据,会产生冲突。而且当一个进程向共享内存区域写入数据后,另外的进程也无法“知道”共享内存的数据发生了变化。因此共享内存通常会与另一种进程通信方式如:信号量组合使用。由信号量实现两个进程的同步,共享内存实现数据的交换。信号量分为互斥信号量与普通信号量,互斥信号量用来解决多个进程(或线程)对共享数据对象访问时的互斥问题;普通信号量(计数信号量
12、或二值信号量)用来解决(进程)线程直接同步通信问题。可以把信号量理解为是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行发送和获取操作。当信号量被发送一次,其数值就增加1,当信号量大于0的时候,等待此信号量的进程会从阻塞状态转为就绪状态,并将信号量减1。进程间通过信号量来实现简单的同步。信号量有命名信号量和匿名信号量,本实验使用命名信号量实现进程间的同步。共享内存的使用流程:l 创建打开共享内存文件并设置文件大小;l 将内存文件映射到实际的物理内存上;l 创建信号量实现使用共享内存通信的两个进程间的同步;l 对内存进行读写操作;l 取消共享内存的内存映射、关闭共享内存文件。2.2.2
13、 消息队列消息被发送到队列中。“消息队列”是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列是内核提供给各个进程之间传递消息的通信机制。消息队列的使用流程:l 使用mq_open 函数创建消息队列,创建队列时会设置消息队列的操作权限和消息关联的键; l 使用mq_send 函数向消息队列发送一个
14、消息;l 使用mq_receive 函数从消息队列中读取一个消息;l 如果不再需要消息通信,使用mq_close 函数关闭此消息队列;l 使用mq_unlink函数删除此消息队列。2.3 进程与线程的比较一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但
15、线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.2) 线程的划分尺度小于进程,使得多线程程序的并发性高。3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独
16、立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。二、基于Qt图形界面的驱动编程实验1. 实验目的l 理解GPIO输入的应用程序设计方法 l 掌握select函数的使用方法l 掌握QtCreater程序的开发流程l 掌握Qt下操作SylixOS硬件设备的方法2. 实验内容l 创建一个Qt工程实现对验证平台GPIO的输出操作l 实现数码管从0000-9999数字的显示l 实现显示数字的
17、加减以及清除操作3. 程序设计流程图4. 程序源代码及注释mainwindow.h#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QThread> /*添加qt线程的头文件*/namespace Ui class MainWindow;/-MainWindow类定义(界面主线程)-class MainWindow : public QMainWindow Q_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); Mai
18、nWindow();private slots: void on_pushButton_clicked(); /加1按键响应函数 void on_pushButton_2_clicked(); /减1按键响应函数 void setnumber(char *p,int i); /int to char 转换 void on_pushButton_3_clicked(); /清零按键响应函数 /* * 添加界面主线程的信号槽函数,用来实现与线程的信号对接 */ void lcdnumValSet(int num); void on_spinBox_editingFinished(); /数字设置窗
19、响应函数private: Ui:MainWindow *ui; /*-用于接收gpio驱动函数返回值的一些变量-*/ int g_led_flag; int status; int fd; int gpioled; int ret;signals: void send(int num); /线程通信函数;/-实体按键监督线程(加1)-class MyThread: public QThread Q_OBJECTpublic: MyThread(); void run(); /线程函数 int fd; /实体数码管的标志位private slots: void setfd(int num); /
20、信号槽函数,用来实现与主线程的信号对接 void setnumber(char *p,int i); /int to char 转换signals: void send(int num); /线程通信函数;/-实体按键监督线程(减1)-class MyThread_sub: public QThread Q_OBJECTpublic: MyThread_sub(); void run(); /线程函数 int fd; /实体数码管的标志位private slots: void setfd(int num); /信号槽函数,用来实现与主线程的信号对接 void setnumber(char *p
21、,int i); /int to char 转换signals: void send(int num); /线程通信函数;/-实体按键监督线程(清零)-class MyThread_clear: public QThread Q_OBJECTpublic: MyThread_clear(); void run(); /线程函数 int fd; /实体数码管的标志位private slots: void setfd(int num); /信号槽函数,用来实现与主线程的信号对接 void setnumber(char *p,int i); /int to char 转换signals: void
22、send(int num); /线程通信函数;#endif / MAINWINDOW_HMainwindow.cpp#include <QMessageBox>#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <sys/select.h>#include <sys/gpiofd.h>#include <string.h>#include <pthread.h>#include <fcntl.h>#inclu
23、de "mainwindow.h"#include "ui_mainwindow.h"#define DIGITLCD_DEVICE "/dev/digitLcd"#define DOWNLOAD_MAX 32#define DLCD_BUF_MAX 16#define DLCD_NUM_MAX 4#define DLCD_CHAR_TAG "CHAR-"#define DLCD_DOT_TAG "DOT-"static UCHAR _G_ucDownloadMapDOWNLOAD_MAX =
24、'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'b', 'C', 'd', 'E', 'F', 'G', 'H', 'i', 'J', 'L', 'o', 'p', &
25、#39;q', 'r', 't', 'U', 'y', 'c', 'h', 'T', 0xFF;int smgnumber = 0; /* 当前显示数值 */pthread_mutex_tlock; /* 互斥锁 */* 类名称: MainWindow* 函数名称: MainWindow* 功能描述: 构造函数*/MainWindow:MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui:MainWindow
26、) ui->setupUi(this); status = 0; gpioled = 24; /*-申请打开数码管-*/ fd = open(DIGITLCD_DEVICE, O_RDWR); if (fd < 0) printf("can NOT open %s, error: %sn", DIGITLCD_DEVICE, strerror(errno); return; /*-创建实体按键监督线程-*/ MyThread *myth = new MyThread; MyThread_sub *myth_sub = new MyThread_sub; MyTh
27、read_clear *myth_clear = new MyThread_clear; /*-建立线程间的通信-*/ connect(myth,SIGNAL(send(int),this,SLOT(lcdnumValSet(int); connect(this,SIGNAL(send(int),myth,SLOT(setfd(int); connect(myth_sub,SIGNAL(send(int),this,SLOT(lcdnumValSet(int); connect(this,SIGNAL(send(int),myth_sub,SLOT(setfd(int); connect(my
28、th_clear,SIGNAL(send(int),this,SLOT(lcdnumValSet(int); connect(this,SIGNAL(send(int),myth_clear,SLOT(setfd(int); /*-运行3个线程-*/ myth->start(); myth_sub->start(); myth_clear->start(); /*-将数码管申请打开的返回值送给各线程-*/ emit send(fd); if (pthread_mutex_init(&lock, NULL) != 0) /* 初始化互斥锁 */ printf("
29、;mutex init failed!n"); return; /* 类名称: MainWindow* 函数名称: MainWindow* 功能描述: 析构函数*/MainWindow:MainWindow() delete ui;/* 类名称: MainWindow* 函数名称: lcdnumValSet* 功能描述: 设置屏幕led计数,界面主线程的信号槽函数,用来实现与线程的信号对接* 输入:int数值*/void MainWindow:lcdnumValSet(int num) ui->lcdNumber->display(num);/* 类名称: MainWin
30、dow、MyThread、MyThread_sub、MyThread_clear(相同代码)* 函数名称: setnumber* 功能描述: 设置计数(int2char),将int数值转换为4位char数组* 输入:char指针、int*/void MainWindow:setnumber(char *p,int i) int n,j; for(j = 0 ; j < 4 ; j+) n = i % 10; i = (i-n)/10; memset(p, _G_ucDownloadMapn, DLCD_NUM_MAX-j); void MyThread:setnumber(char *p
31、,int i) int n,j; for(j = 0 ; j < 4 ; j+) n = i % 10; i = (i-n)/10; memset(p, _G_ucDownloadMapn, DLCD_NUM_MAX-j); void MyThread_sub:setnumber(char *p,int i) int n,j; for(j = 0 ; j < 4 ; j+) n = i % 10; i = (i-n)/10; memset(p, _G_ucDownloadMapn, DLCD_NUM_MAX-j); void MyThread_clear:setnumber(cha
32、r *p,int i) int n,j; for(j = 0 ; j < 4 ; j+) n = i % 10; i = (i-n)/10; memset(p, _G_ucDownloadMapn, DLCD_NUM_MAX-j); /* 类名称: MainWindow* 函数名称: on_pushButton_clicked* 功能描述: 加1按键响应函数*/void MainWindow:on_pushButton_clicked() pthread_mutex_lock(&lock); /* 对资源上锁 */ printf("addn"); smgnum
33、ber+; /* 加1 */ if(smgnumber>=10000) smgnumber=0; char *pbuf; char bufDLCD_BUF_MAX; strcpy(buf, DLCD_CHAR_TAG); pbuf = buf + strlen(DLCD_CHAR_TAG); setnumber(pbuf,smgnumber); /* int2char */ ui->lcdNumber->display(smgnumber); /* 屏幕显示 */ ret = write(fd, buf, (strlen(DLCD_CHAR_TAG) + DLCD_NUM_M
34、AX); /* 实际数码管显示显示 */ if (ret > 0) /printf("Show key: %c n", _G_ucDownloadMapi); else printf("write char errorn"); return; pthread_mutex_unlock(&lock); /* 对资源解锁 */* 类名称: MainWindow* 函数名称: on_pushButton_2_clicked* 功能描述: 减1按键响应函数*/void MainWindow:on_pushButton_2_clicked() pth
35、read_mutex_lock(&lock); /* 对资源上锁 */ printf("sbbn"); if(smgnumber<=0) smgnumber=10000; smgnumber-; /* 减1 */ char *pbuf; char bufDLCD_BUF_MAX; strcpy(buf, DLCD_CHAR_TAG); pbuf = buf + strlen(DLCD_CHAR_TAG); setnumber(pbuf,smgnumber); /* int2char */ ui->lcdNumber->display(smgnumb
36、er); /* 屏幕显示 */ ret = write(fd, buf, (strlen(DLCD_CHAR_TAG) + DLCD_NUM_MAX); /* 实际数码管显示显示 */ if (ret > 0) /printf("Show key: %c n", _G_ucDownloadMapi); else printf("write char errorn"); return; pthread_mutex_unlock(&lock); /* 对资源解锁 */* 类名称: MainWindow* 函数名称: on_pushButton_
37、3_clicked* 功能描述: 清零按键响应函数*/void MainWindow:on_pushButton_3_clicked() pthread_mutex_lock(&lock); /* 对资源上锁 */ printf("clearn"); smgnumber=0; /* 清零 */ char *pbuf; char bufDLCD_BUF_MAX; strcpy(buf, DLCD_CHAR_TAG); pbuf = buf + strlen(DLCD_CHAR_TAG); setnumber(pbuf,smgnumber); /* int2char *
38、/ ui->lcdNumber->display(smgnumber); /* 屏幕显示 */ ret = write(fd, buf, (strlen(DLCD_CHAR_TAG) + DLCD_NUM_MAX); /* 实际数码管显示显示 */ if (ret > 0) /printf("Show key: %c n", _G_ucDownloadMapi); else printf("write char errorn"); return; pthread_mutex_unlock(&lock); /* 对资源解锁 */*
39、 类名称: MyThread* 函数名称: MyThread* 功能描述: 构造函数*/MyThread:MyThread()/* 类名称: MyThread* 函数名称: run* 功能描述: 进程函数,实现实体按键加1功能*/void MyThread:run() int ret; int fd_button; fd_set fdset; int gpio_in_num= 36; /*-申请打开按键-*/ fd_button = gpiofd(gpio_in_num, 0, GPIO_FLAG_TRIG_FALL | GPIO_FLAG_TRIG_RISE); if (fd_button
40、<= 0) printf("gpiofd create error!"); return ; FD_ZERO(&fdset); /*-监督过程(死循环)-*/ while (1) FD_SET(fd_button, &fdset); /*-进入阻塞,等待按键被按下-*/ ret = select(fd_button + 1, &fdset, NULL, NULL, NULL); /*-按键被按下后,执行响应-*/ if (ret = 1) pthread_mutex_lock(&lock); /* 对资源上锁 */ printf("addn"); smgnumber+; /* 加1 */ if(smgnumber>=10000) smgnumber=0; char *pbuf; char bufDLCD_BUF_MAX; strcpy(buf, DLCD_CHAR_TAG); pbuf = buf + strlen(DLCD_CHAR_TAG); setnumber(pbuf,smgnumber); /* int2char */ ret = write(fd, buf, (strlen(DLCD_CHAR_TAG) + DLCD_NUM_MAX
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 【讲练通】2021版高中历史岳麓版必修1-单元质量评估(三)
- 六年级上册数学教研组工作计划范文评价
- 【学练考】2021-2022苏教版化学必修1练习-专题3-从矿物到基础材料
- 三年级数学(上)计算题专项练习附答案
- 五年级数学(小数乘除法)计算题专项练习及答案汇编
- 全程方略2021届高考数学专项精析精炼:2014年考点48-随机事件的概率、古典概型、几何概型
- 家长进课堂小学生食品安演示教学
- 增塑剂聚酯薄膜行业分析
- 2018-2019学年高中生物-第三章-遗传的分子基础本章知识体系构建课件-浙科版必修2
- (期末押题卷)期末重难点高频易错培优卷(试题)-2024-2025学年四年级上册数学人教版
- 【小米公司财务共享服务中心的构建与运行探究8200字(论文)】
- 成人癌性疼痛护理-中华护理学会团体标准2019
- 劳动保障监察条例
- 2023年建筑继续教育考试:安全员继续教育真题模拟汇编(共830题)
- 冷却塔验收表
- 外科科主任工作计划
- 施工图设计提资管控细则
- 人教部编版八年级语文上册名著导读《红星照耀中国》复习素材
- 【个人简历】大学生职业生涯规划书10篇
- 患者满意度调查分析
- 印刷公司绩效考核KPI指标库
评论
0/150
提交评论