Linux多线程——生产者消费者模型

目录

一.生产者消费者模型

        1.1 什么是生成者消费者模型

        1.2 生产者消费者模型的优点

        1.3 基于阻塞队列实现生产者消费者模型

         1.4 POSIX信号量

        1.4.1 信号量概念

        1.4.2 P操作和V操作

        1.4.3 理解信号量

        1.4.4 信号量的函数

         1.4.5 基于环形队列实现生产者消费者模型


一.生产者消费者模型

        1.1 什么是生成者消费者模型

        一个进程中的线程有两种角色,一种是生产者,一种是消费者。生产者为消费者提供任务,消费者拿到任务,解决任务。在生成者和消费者之间还有一个"交易场所",是一个内存块。生成者线程将任务放到内存块中,消费者线程在内存块中拿任务。当内存块数据达到一高水位线时,生产者会进行等待,唤醒消费者拿任务,当内存块数据达到一低水位线时,消费者会等待,并且唤醒生产者生产任务。

        生成者,消费者存在着3种关系。生产者和生产者之间是互斥的关系,消费者和消费者之间是互斥的关系,生产者和消费者之间是互斥和同步的关系。

        1.2 生产者消费者模型的优点

        例如一个正常的函数,不使用生产者消费者模型:

       上面是单线程的情况,即使是多线程,不使用生产者消费者模型,生产者直接给消费者送数据,整个进程的效率会是最慢的线程的效率。并且只能生产一个数据,消费一个数据。两者还是串行的,耦合度高。

        使用生产者消费者模型:

生产者和消费者模型的优点:

  • 实现线程的解耦
  • 支持线程之间并行运行
  • 效率高
  • 方便代码维护

        1.3 基于阻塞队列实现生产者消费者模型

        在多线程编程中,阻塞队列是一种常用于实现生产者和消费者模型的数据结构。其普通队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入元素,当队列满的时候,往队列中存放元素的操作也会被阻塞,直到有元素从队列中取出。

生产者和生产者之间互斥,消费者和消费者之间互斥

    在生产和消费的时候需要定义两个互斥量,一个是生产者之间的,一个是消费者之间的。

生产者和消费者之间互斥且同步

    定义一个互斥量,取数据的时候,不能放,放数据的时候,不能取

   有两个条件,满和空,定义两个条件变量

实现的是多生产者,多消费者的模型。

注意:编码时,要先环境再等待,不然能就唤醒不了了。

#pragma once 

#include<iostream>
#include<queue>
#include<pthread.h>
//队列元素个刷
#define NUM 5
//任务
struct Task{
  Task(){};
  Task(int x,int y)
    :_x(x)
    ,_y(y)
  {}
  int _x;
  int _y;
  int Add(){
    return _x + _y;
  }
};
//提供两个接口,放任务,和拿任务
class blockqueue{
private:
  //加锁
  void MakeLock(){
    pthread_mutex_lock(&_lock);
  }
  //取消锁
  void CancelLock(){
    pthread_mutex_unlock(&_lock);
  }
  //唤醒消费者
  void WakeUpConsumer(){
    std::cout<<"Consumer wake up"<<std::endl;
    pthread_cond_signal(&_empty);

  }
  //唤醒生产者
  void WakeUpProductor(){
    std::cout<<"Productor wake up"<<std::endl;
    pthread_cond_signal(&_full);

  }
  //生产者等待
  void SleepProductor(){
    std::cout<<"Productor sleep"<<std::endl;
    pthread_cond_wait(&_full, &_lock);

  }
  //消费者等待
  void SleepConsumer(){
    std::cout<<"Consumer sleep"<<std::endl;
    pthread_cond_wait(&_empty, &_lock);

  }

public:
  blockqueue(size_t cap = NUM)
    :_cap(cap)
  {
    pthread_mutex_init(&_lock, nullptr);
    pthread_cond_init(&_full, nullptr);
    pthread_cond_init(&_empty, nullptr);
  }
  ~blockqueue(){
    pthread_cond_destroy(&_empty);
    pthread_cond_destroy(&_full);
    pthread_mutex_destroy(&_lock);

  }
  //放数据
  void Put(Task in){
    //q队列是临界资源,需要加锁
    MakeLock();
    //需要使用循环
    while(_q.size()>=_cap){
    //先唤醒再等待
      WakeUpConsumer();
      SleepProductor();
    }
    _q.push(in);
    CancelLock();

  }
  //获取数据
  void Get(Task& out){
    MakeLock();
    while(_q.empty()){
      WakeUpProductor();
      SleepConsumer();
    }
    out=_q.front();
    _q.pop();
    CancelLock();

  }

private:
  std::queue<Task> _q;
  size_t _cap;
  pthread_mutex_t _lock;
  pthread_cond_t _empty;//消费者在此等待
  pthread_cond_t _full;//生产者在此等待

};


#include"BlockQueue.hpp"
#include<unistd.h>

#define PRO 2
#define CON 2
using namespace std;
//定义两个互斥量,生产者和消费者之间要互相竞争锁
//决定哪个线程进来
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;

void *Productor(void *arg){
  sleep(1);
  blockqueue *q = (blockqueue *)arg;
  while(true){
    sleep(1);
    int x=rand()%9+1;
    int y=rand()%20+1;
    Task t(x,y);
	//阻塞队列是共享资源,需要上锁
    pthread_mutex_lock(&mutex2);
    q->Put(t);
    cout<<pthread_self()<<":"<<x<<"+"<<y<<"="<<"?"<<endl;
    pthread_mutex_unlock(&mutex2);
  }
}
void *Consumer(void *arg){
  blockqueue *q = (blockqueue *)arg;
  while(true){
    sleep(1);
    Task t;
	//阻塞队列是共享资源,需要上锁
    pthread_mutex_lock(&mutex1);
    q->Get(t);
    cout<<pthread_self()<<":"<<t._x<<"+"<<t._y<<"="<<t.Add()<<endl;
    pthread_mutex_unlock(&mutex1);
  }

}

int main(){
  pthread_mutex_init(&mutex2,nullptr);
  pthread_mutex_init(&mutex1,nullptr);
  blockqueue *bq = new blockqueue();
  //生产者线程
  pthread_t td1[PRO];
  int i=0;
  for(; i<PRO; i++){
    pthread_create(td1+i, nullptr, Productor, (void *)bq);
  }
  //消费者线程
  pthread_t td2[CON];
  for(i=0; i<CON; i++){
    pthread_create(td2+i, nullptr, Consumer, (void *)bq);
  } 
  
  for(i=0; i<PRO; i++){
    pthread_join(td1[i], nullptr);
  }
  for(i=0; i<CON; i++){
    pthread_join(td2[i], nullptr);
  }
  pthread_mutex_destroy(&mutex2);
  pthread_mutex_destroy(&mutex1);
  delete bq;
  return 0;
}

 演示:

         1.4 POSIX信号量

        1.4.1 信号量概念

        有一种情况,我们可以将临界资源分成若干份,一个线程只会使用临界资源中的一份。

        这个时候就有了信号量,信号量本质是一个计数器,描述的是临界资源的有效个数。

        1.4.2 P操作和V操作

        假如:临界资源可以分成5个部分,记为count=5。count就被称作信号量。

        count--,一个执行流占有一个部分的操作叫做P操作。

        count++,一个执行流结束使用临界资源的一部风叫做V操作。

        当信号量count==0时,如果进行P操作,没有信号量可以分配了,此时会阻塞等待。

        由于信号量每一个线程看到的是同一份资源,信号量也是临界资源,要保证P,V操作是原子的。

        二元信号量相当于互斥锁: 二元信号量只有1个信号量,只要一个线程占有,信号量的值就等于0,其它线程就需要等待。

        1.4.3 理解信号量

        OS中会有很多的信号量,OS系统需要对它们进行管理,管理需要进行描述:

信号量可以描述为:

struct sem{

......

int count;//临界资源有效个数

mutex lock;//只允许一个线程对临界资源进行操作,需要上锁

wait_queue *head;//等待队列

......

}

        1.4.4 信号量的函数

  • 初始化
#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
作用:初始化信号量
参数:
    sem,要初始化的信号量
    pshared:0表示线程间共享,非0表示进程间共享
    value:信号量初始值,信号量个数
  • 销毁信号量
#include <semaphore.h>

int sem_destroy(sem_t *sem);
作用:销毁定义的信号量
参数:
    sem:要销毁的信号量
  • 等待信号量,P操作
 #include <semaphore.h>

int sem_wait(sem_t *sem);
作用:等待信号量,将信号量的值减1,如果信号量为0,阻塞等待
参数:
    sem:要等待的信号量

  • 发布信号,V操作
#include <semaphore.h>
int sem_post(sem_t *sem);

作用:表示资源使用完毕,将信号量做加1操作
参数:
    sem:要发布的信号量

         1.4.5 基于环形队列实现生产者消费者模型

  • 环形队列采用数组模拟,用模运算来模拟环形特征
  • 当队列满了或者队列为空时,都是消费者的下标和生产者的下标相同。不好判断为空和满的情况。
    • 有两种方法:
    • 1.少用一个元素空间,这个时候为空时,下标相等,为满时,生产者下标加1在取模等于消费者下标。
    • 2.增加一个计数器,来记录元素个数。
  • 我们这里正好有信号量这个计数器,队列里的每一个位置代表一个信号量。正好信号量就是这个计数器。

定义两个信号量,一个信号量表示空格字space_sem,一个信号量表示数据_data_sem。

生产者:放元素,关注的说空格子这个信号量。

伪代码:

        P(space_sem)

        生产数据

        V(data_sem)

消费者:拿元素,关注的是数据这个信号量。 

伪代码:

        P(data_sem)

        生产数据

        V(space_sem)

        执行到同一位置时,为空或者满,此时要不就是space_sem为临界资源总有效个数,data_sem为0,要不就是data_sem为临界资源总有效个数,space_sem为0。这个时候,放数据和拿数据总会有一个在等待(P操作)。

        当生产者快,消费者慢时,一开始生产者将数据放满,在消费者消费一个,在生产者生产一个。队列经常是满的。

        当生产者,消费者快时,一开始没数据,需要生产者生产,在消费一个,现象时生产一个消费一个,队列经常是空的。

多消费者多生产者:

#pragma once 
#include<iostream>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
#define NUM 5

class RingQueue{
  private:
    void P(sem_t& s){
      //信号量减减操作,如果为0等待
      sem_wait(&s);
    }
    void V(sem_t& s){
      //信号量加加操作
      sem_post(&s);
    }
  public:
    RingQueue(size_t cap = NUM)
      :_v(cap)
      ,_cap(cap)
      ,_cindex(0)
      ,_pindex(0)
      {
        sem_init(&_space_sem, 0, cap);
        sem_init(&_data_sem, 0, 0);
      }

    void Put(const int& in){
      //生产者关注格子数
      P(_space_sem);
      _v[_pindex]=in;
      _pindex++;
      _pindex %= _cap;
      V(_data_sem);

    }
    void Get(int& out){
      //消费者关注数据
      P(_data_sem);
      out = _v[_cindex];
      _cindex++;
      _cindex %= _cap;
      V(_space_sem);

    }

    ~RingQueue(){
      sem_destroy(&_space_sem);
      sem_destroy(&_data_sem);
      _cindex = 0;
      _pindex = 0;
    }

  private:
    std::vector<int> _v;//队列
    size_t _cap;//队列容量
    sem_t _space_sem;//格子信号量
    sem_t _data_sem;//数据信号量
    
    int _cindex;//消费者位置
    int _pindex;//生产者位置

};
#include"RingQueue.hpp"
#include<unistd.h>

using namespace std;

#define CON 4
#define PRO 4

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
void *consumer(void *arg){
  RingQueue *rq=(RingQueue *)arg;
  while(1){
    sleep(1);
    int x=0;
    pthread_mutex_lock(&mutex1);
    rq->Get(x);
    pthread_mutex_unlock(&mutex1);
    cout<<pthread_self()<<":"<<"consumer get a data :"<<x<<endl;

  }
}

void *productor(void *arg){
  RingQueue *rq=(RingQueue *)arg;
  while(1){
    //sleep(1);
    int x=rand()%10+1;
    pthread_mutex_lock(&mutex2);
    rq->Put(x);
    pthread_mutex_unlock(&mutex2);
    cout<<pthread_self()<<":"<<"productor put a data :"<<x<<endl;

  }
}
int main(){
  RingQueue *rq = new RingQueue();
  pthread_t td1[CON];
  pthread_t td2[PRO];
  int i=0;
  for(; i<CON; i++){
    pthread_create(td1+i, nullptr, consumer, (void *)rq);
  }
  for(i=0; i<PRO; i++){
    pthread_create(td2+i, nullptr, productor, (void *)rq);
  }
  

  for(i=0; i<CON; i++){
    pthread_join(td1[i], nullptr);
  }
  for(i=0; i<PRO; i++){
    pthread_join(td2[i], nullptr);
  }
  delete rq;

  return 0;
}

  • 4
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
《嵌入式Linux应用程序开发标准教程(第2版)》主要分为3个部分,包括Linux基础、搭建嵌入式Linux环境和嵌入式Linux的应用开发。Linux基础部分从Linux基础、基本操作命令讲起,为Linux初学者能快速入门提供了保证。接着系统地讲解了嵌入式Linux的环境搭建,以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及嵌入式图形界面的开发等,并且还安排了丰富的实验内容与课后实践,使读者能够边学边用,更快更好地掌握所学知识。   《嵌入式Linux应用程序开发标准教程(第2版)》可作为高等院校电子类、电气类、控制类等专业高年级本科生、研究生学习嵌入式Linux的教材,也可供希望转入嵌入式领域的科研和工程技术人员参考使用,还可作为嵌入式培训班的教材和参考书。 第1章 Linux快速入门 1.1 嵌入式Linux基础 1.1.1 Linux发展概述 1.1.2 Linux作为嵌入式操作系统的优势 1.1.3 Linux发行版本 1.1.4 如何学习Linux 1.2 Linux安装 1.2.1 基础概念 1.2.2 硬件需求 1.2.3 安装准备 1.3 Linux文件及文件系统 1.3.1 文件类型及文件属性 1.3.2 文件系统类型介绍 1.3.3 Linux目录结构 1.4 实验内容——安装Linux操作系统 1.5 本章小结 1.6 思考与练习 第2章 Linux基础命令 2.1 Linux常用命令 2.1.1 用户系统相关命令 2.1.2 文件相关命令 2.1.3 压缩打包相关命令 2.1.4 文件比较合并相关命令 2.1.5 网络相关命令 2.2 Linux启动过程详解 2.2.1 概述 2.2.2 内核引导阶段 2.2.3 init阶段 2.3 Linux系统服务 2.3.1 独立运行的服务 2.3.2 xinetd设定的服务 2.3.3 系统服务的其他相关命令 2.4 实验内容 2.4.1 在Linux下解压常见软件 2.4.2 定制Linux系统服务 2.5 本章小结 2.6 思考与练习 第3章 Linux下C编程基础 3.1 Linux下C语言编程概述 3.1.1 C语言简单回顾 3.1.2 Linux下C语言编程环境概述 3.2 常用编辑器 3.2.1 进入vi 3.2.2 初探emacs 3.3 gcc编译器 3.3.1 gcc编译流程解析 3.3.2 gcc编译选项分析 3.4 gdb调试器 3.4.1 gdb使用流程 3.4.2 gdb基本命令 3.5 make工程管理器 3.5.1 makefile基本结构 3.5.2 makefile变量 3.5.3 makefile规则 3.5.4 make管理器的使用 3.6 使用autotools 3.6.1 autotools使用流程 3.6.2 使用autotools所生成的makefile 3.7 实验内容 3.7.1 vi使用练习 3.7.2 用gdb调试程序的bug 3.7.3 编写包含多文件的makefile 3.7.4 使用autotools生成包含多文件的makefile 3.8 本章小结 3.9 思考与练习 第4章 嵌入式系统基础 4.1 嵌入式系统概述 4.1.1 嵌入式系统简介 4.1.2 嵌入式系统发展历史 4.1.3 嵌入式系统的特点 4.1.4 嵌入式系统的体系结构 4.1.5 几种主流嵌入式操作系统分析 4.2 ARM处理器硬件开发平台 4.2.1 ARM处理器简介 4.2.2 ARM体系结构简介 4.2.3 ARM9体系结构 4.2.4 S3C2410处理器详解 4.3 嵌入式软件开发流程 4.3.1 嵌入式系统开发概述 4.3.2 嵌入式软件开发概述 4.4 实验内容——使用JTAG烧写NandFlash 4.5 本章小结 4.6 思考与练习 第5章 嵌入式Linux开发环境的搭建 5.1 嵌入式开发环境的搭建 5.1.1 嵌入式交叉编译环境的搭建 5.1.2 超级终端和minicom配置及使用 5.1.3 下载映像到开发板 5.1.4 编译嵌入式Linux内核 5.1.5 Linux内核源码目录结构 5.1.6 制作文件系统 5.2 U-Boot移植 5.2.1 Bootloader介绍 5.2.2 U-Boot概述 5.2.3 U-Boot源码导读 5.2.4 U-Boot移植主要步骤 5.3 实验内容——创建Linux内核和文件系统 5.4 本章小结 5.5 思考与练习 第6章 文件I/O编程 6.1 Linux系统调用及用户编程接口(API) 6.1.1 系统调用 6.1.2 用户编程接口(API) 6.1.3 系统命令 6.2 Linux中文件及文件描述符概述 6.3 底层文件I/O操作 6.3.1 基本文件操作 6.3.2 文件锁 6.3.3 多路复用 6.4 嵌入式Linux串口应用编程 6.4.1 串口概述 6.4.2 串口设置详解 6.4.3 串口使用详解 6.5 标准I/O编程 6.5.1 基本操作 6.5.2 其他操作 6.6 实验内容 6.6.1 文件读写及上锁 6.6.2 多路复用式串口操作 6.7 本章小结 6.8 思考与练习 第7章 进程控制开发 7.1 Linux进程概述 7.1.1 进程的基本概念 7.1.2 Linux下的进程结构 7.1.3 Linux下进程的模式和类型 7.1.4 Linux下的进程管理 7.2 Linux进程控制编程 7.3 Linux守护进程 7.3.1 守护进程概述 7.3.2 编写守护进程 7.3.3 守护进程的出错处理 7.4 实验内容 7.4.1 编写多进程程序 7.4.2 编写守护进程 7.5 本章小结 7.6 思考与练习 第8章 进程间通信 8.1 Linux下进程间通信概述 8.2 管道 8.2.1 管道概述 8.2.2 管道系统调用 8.2.3 标准流管道 8.2.4 FIFO 8.3 信号 8.3.1 信号概述 8.3.2 信号发送与捕捉 8.3.3 信号的处理 8.4 信号量 8.4.1 信号量概述 8.4.2 信号量的应用 8.5 共享内存 8.5.1 共享内存概述 8.5.2 共享内存的应用 8.6 消息队列 8.6.1 消息队列概述 8.6.2 消息队列的应用 8.7 实验内容 8.7.1 管道通信实验 8.7.2 共享内存实验 8.8 本章小结 8.9 思考与练习 第9章 多线程编程 9.1 Linux线程概述 9.1.1 线程概述 9.1.2 线程机制的分类和特性 9.2 Linux线程编程 9.2.1 线程基本编程 9.2.2 线程之间的同步与互斥 9.2.3 线程属性 9.3 实验内容——“生产者消费者”实验 9.4 本章小结 9.5 思考与练习 第10章 嵌入式Linux网络编程 10.1 TCP/IP概述 10.1.1 OSI参考模型及TCP/IP参考模型 10.1.2 TCP/IP协议族 10.1.3 TCP和UDP 10.2 网络基础编程 10.2.1 socket概述 10.2.2 地址及顺序处理 10.2.3 socket基础编程 10.3 网络高级编程 10.4 实验内容——NTP协议实现 10.5 本章小结 10.6 思考与练习 第11章 嵌入式Linux设备驱动开发 11.1 设备驱动概述 11.1.1 设备驱动简介及驱动模块 11.1.2 设备分类 11.1.3 设备号 11.1.4 驱动层次结构 11.1.5 设备驱动程序与外界的接口 11.1.6 设备驱动程序的特点 11.2 字符设备驱动编程 11.3 GPIO驱动程序实例 11.3.1 GPIO工作原理 11.3.2 GPIO驱动程序 11.4 块设备驱动编程 11.5 中断编程 11.6 按键驱动程序实例 11.6.1 按键工作原理 11.6.2 按键驱动程序 11.6.3 按键驱动的测试程序 11.7 实验内容——test驱动 11.8 本章小结 11.9 思考与练习 第12章 Qt图形编程基础 12.1 嵌入式GUI简介 12.1.1 Qt/Embedded 12.1.2 MiniGUI 12.1.3 Microwindows、TinyX等 12.2 Qt/Embedded开发入门 12.2.1 Qt/Embedded介绍 12.2.2 Qt/Embedded信号和插槽机制 12.2.3 搭建Qt/Embedded开发环境 12.2.4 Qt/Embedded窗口部件 12.2.5 Qt/Embedded图形界面编程 12.2.6 Qt/Embedded对话框设计 12.3 实验内容——使用Qt编写“Hello,World”程序 12.4 本章小结
目录 第1章 Linux快速入门 1 1.1 嵌入式Linux基础 1 1.1.1 Linux发展概述 1 1.1.2 Linux作为嵌入式操作系统的优势 2 1.1.3 Linux发行版本 3 1.1.4 如何学习Linux 4 1.2 Linux安装 5 1.2.1 基础概念 5 1.2.2 硬件需求 7 1.2.3 安装准备 7 1.2.4 安装过程 8 1.3 Linux文件及文件系统 11 1.3.1 文件类型及文件属性 11 1.3.2 文件系统类型介绍 13 1.3.3 Linux目录结构 14 1.4 实验内容——安装Linux操作系统 17 本章小结 17 思考与练习 18 第2章 Linux基础命令 19 2.1 Linux常用操作命令 19 2.1.1 用户系统相关命令 20 2.1.2 文件目录相关命令 27 2.1.3 压缩打包相关命令 38 2.1.4 比较合并文件相关命令 40 2.1.5 网络相关命令 45 2.2 Linux启动过程详解 50 2.2.1 概述 51 2.2.2 内核引导阶段 51 2.2.3 init阶段 52 2.3 Linux系统服务 54 2.3.1 独立运行的服务 55 2.3.2 xinetd设定的服务 56 2.3.3 设定服务命令常用方法 56 2.4 实验内容 57 2.4.1 在Linux下解压常见软件 57 2.4.2 定制Linux系统服务 58 本章小结 60 思考与练习 60 第3章 Linux下的C编程基础 61 3.1 Linux下C语言编程概述 61 3.1.1 C语言简单回顾 61 3.1.2 Linux下C语言编程环境概述 62 3.2 进入Vi 63 3.2.1 Vi的模式 63 3.2.2 Vi的基本流程 63 3.2.3 Vi的各模式功能键 65 3.3 初探Emacs 66 3.3.1 Emacs的基本操作 67 3.3.2 Emacs的编译概述 70 3.4 Gcc编译器 71 3.4.1 Gcc编译流程解析 71 3.4.2 Gcc编译选项分析 74 3.5 Gdb调试器 77 3.5.1 Gdb使用流程 78 3.5.2 Gdb基本命令 81 3.6 Make工程管理器 86 3.6.1 Makefile基本结构 86 3.6.2 Makefile变量 87 3.6.3 Makefile规则 90 3.6.4 Make管理器的使用 91 3.7 使用autotools 92 3.7.1 autotools使用流程 92 3.7.2 使用autotools所生成的Makefile 96 3.8 实验内容 98 3.8.1 Vi使用练习 98 3.8.2 用Gdb调试有问题的程序 99 3.8.3 编写包含多文件的Makefile 101 3.8.4 使用autotools生成包含多文件的Makefile 103 本章小结 105 思考与练习 105 第4章 嵌入式系统基础 106 4.1 嵌入式系统概述 106 4.1.1 嵌入式系统简介 106 4.1.2 嵌入式系统发展历史 107 4.1.3 嵌入式系统的特点 108 4.1.4 嵌入式系统的体系结构 108 4.1.5 几种主流嵌入式操作系统分析 109 4.2 ARM处理器硬件开发平台 111 4.2.1 ARM处理器简介 111 4.2.2 ARM体系结构简介 113 4.2.3 ARM9体系结构 113 4.2.4 S3C2410处理器详解 116 4.3 嵌入式软件开发流程 121 4.3.1 嵌入式系统开发概述 121 4.3.2 嵌入式软件开发概述 122 4.4 实验内容——使用JTAG烧写NAND Flash 128 本章小结 131 思考与练习 132 第5章 嵌入式Linux开发环境的搭建 133 5.1 嵌入式开发环境的搭建 133 5.1.1 嵌入式交叉编译环境的搭建 133 5.1.2 超级终端和Minicom配置及使用 135 5.1.3 下载映像到开发板 142 5.1.4 编译嵌入式Linux内核 145 5.1.5 Linux内核目录结构 149 5.1.6 制作文件系统 149 5.2 U-Boot移植 153 5.2.1 Bootloader介绍 153 5.2.2 U-Boot概述 155 5.2.3 U-Boot源码导读 156 5.2.4 U-Boot移植主要步骤 163 5.2.5 U-Boot常见命令 164 5.3 实验内容——移植Linux内核 164 本章小结 165 思考与练习 165 第6章 文件I/O编程 166 6.1 Linux系统调用及用户编程接口(API) 166 6.1.1 系统调用 166 6.1.2 用户编程接口(API) 167 6.1.3 系统命令 167 6.2 Linux中文件及文件描述符概述 168 6.3 不带缓存的文件I/O操作 168 6.3.1 open和close 168 6.3.2 read、write和lseek 170 6.3.3 fcntl 173 6.3.4 select 178 6.4 嵌入式Linux串口应用开发 183 6.4.1 串口概述 183 6.4.2 串口设置详解 184 6.4.3 串口使用详解 191 6.5 标准I/O开发 194 6.5.1 打开和关闭文件 194 6.5.2 文件读写 197 6.5.3 输入输出 198 6.6 实验内容 201 6.6.1 文件读写及上锁 201 6.6.2 多路复用式串口读写 204 本章小结 207 思考与练习 207 第7章 进程控制开发 208 7.1 Linux下进程概述 208 7.1.1 进程相关基本概念 208 7.1.2 Linux下的进程结构 210 7.1.3 Linux下进程的模式和类型 210 7.1.4 Linux下的进程管理 211 7.2 Linux进程控制编程 212 7.3 Linux守护进程 224 7.3.1 守护进程概述 224 7.3.2 编写守护进程 224 7.3.3 守护进程的出错处理 229 7.4 实验内容 232 7.4.1 编写多进程程序 232 7.4.2 编写守护进程 235 本章小结 238 思考与练习 239 第8章 进程间通信 240 8.1 Linux下进程间通信概述 240 8.2 管道通信 241 8.2.1 管道概述 241 8.2.2 管道创建与关闭 242 8.2.3 管道读写 244 8.2.4 标准流管道 246 8.2.5 FIFO 249 8.3 信号通信 253 8.3.1 信号概述 253 8.3.2 信号发送与捕捉 255 8.3.3 信号的处理 258 8.4 共享内存 264 8.4.1 共享内存概述 264 8.4.2 共享内存实现 265 8.5 消息队列 267 8.5.1 消息队列概述 267 8.5.2 消息队列实现 268 8.6 实验内容 272 8.6.1 管道通信实验 272 8.6.2 共享内存实验 275 本章小结 277 思考与练习 278 第9章 多线程编程 279 9.1 Linux下线程概述 279 9.1.1 线程概述 279 9.1.2 线程分类 280 9.1.3 Linux线程技术的发展 280 9.2 Linux线程实现 281 9.2.1 线程基本操作 281 9.2.2 线程访问控制 288 9.3 实验内容——“生产者消费者”实验 298 本章小结 302 思考与练习 303 第10章 嵌入式Linux网络编程 304 10.1 TCP/IP协议概述 304 10.1.1 OSI参考模型及TCP/IP参考模型 304 10.1.2 TCP/IP协议族 305 10.1.3 TCP和UDP 306 10.2 网络基础编程 308 10.2.1 socket概述 308 10.2.2 地址及顺序处理 309 10.2.3 socket基础编程 314 10.3 网络高级编程 322 10.4 ping源码分析 326 10.4.1 ping简介 326 10.4.2 ping源码分析 327 10.5 实验内容——NTP协议实现 345 本章小结 352 思考与练习 352 第11章 嵌入式Linux设备驱动开发 353 11.1 设备驱动概述 353 11.1.1 设备驱动简介及驱动模块 353 11.1.2 设备文件分类 354 11.1.3 设备号 355 11.1.4 驱动层次结构 355 11.1.5 设备驱动程序与外界的接口 355 11.1.6 设备驱动程序的特点 356 11.2 字符设备驱动编写 356 11.3 LCD驱动编写实例 363 11.3.1 LCD工作原理 363 11.3.2 LCD驱动实例 365 11.4 块设备驱动编写 374 11.4.1 块设备驱动程序描述符 374 11.4.2 块设备驱动编写流程 375 11.5 中断编程 381 11.6 键盘驱动实现 382 11.6.1 键盘工作原理 382 11.6.2 键盘驱动综述 383 11.6.3 键盘驱动流程 384 11.7 实验内容——skull驱动 394 本章小结 398 思考与练习 399 第12章 Qt图形编程 400 12.1 嵌入式GUI简介 400 12.1.1 Qt/Embedded 401 12.1.2 MiniGUI 401 12.1.3 Microwindows、Tiny X等 402 12.2 Qt/Embedded开发入门 402 12.2.1 Qt/Embedded介绍 402 12.2.2 Qt/Embedded信号和插槽机制 405 12.2.3 搭建Qt/Embedded开发环境 409 12.2.4 Qt/Embedded窗口部件 410 12.2.5 Qt/Embedded图形界面编程 414 12.2.6 Qt/Embedded对话框设计 416 12.3 实验内容——使用Qt编写“Hello,World”程序 420 本章小结 428

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值