线程、进程与开发板

线程(thread)

1.线程概述

线程是包含在进程内部顺序执行流,是进程中的实际运作单位,是操作系统能够进行调度基本单位。

2.线程管理

创建线程 pthread_create( )

int pthread_create(
      	pthread_t *thread, 
		const pthread_attr_t *attr,
		void *(*start_routine)(void*),
	  	void *arg
); 

参数说明:

  • thread 指针指向新线程ID结构体;
  • attr 含有各种线程属性的属性对象;
  • start_routine 线程开始执行时调用的函数名;
  • arg 给start_routine函数提供参数,类型为void *.
  • 返回值 成功返回0,否则返回错误码。

终止线程 pthread_exit( )

void pthread_exit(void *retval);
  • retval是一个void类型的指针,可以将线程的返回值当作pthread_exit( )的参数传入。
  • 在创建的线程的顶层执行return线程会隐式地调用pthread_exit( )。

线程ID (tid)

  • 线程ID可以看作为线程的句柄,用来引用一个线程。类型pthread_t,是一个结构体;
  • 获取线程自身ID:
    通过函数:my_tid = pthread_self( )
    函数原型:pthread_t pthread_self(void);
  • 比较线程ID是否相等:
    pthread_equal( )函数

线程创建与终止示例

请添加图片描述
运行结果如下:
请添加图片描述

线程连接与分离

  • 连接与分离线程
    线程可以分为分离线程(DETACHED)和非分离线程(JOINABLE)两种:
  • 线程分离
    函数原型:
int pthread_detach(pthread_t thread);
  • 线程连接
    函数原型:
int pthread_join(pthread_t thread, void**retavl);

线程连接与分离示例

请添加图片描述
运行结果如下图所示:
请添加图片描述

线程初始化与销毁

基本的线程属性包括:栈大小、调度策略和状态属性封装于属性结构体(pthread_attr_t结构体类型)中,其中初始化及销毁函数为:

  • 初始化
int pthread_attr_init(pthread_attr_t *attr);
  • 销毁
int pthread_attr_destroy(pthread_attr_t *attr);

线程初始化与销毁示例

请添加图片描述

创建与销毁函数原型

  • 静态初始化
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 动态初始化
    int pthread_mutex_init( );
  • 销毁
    int pthread_mutex_destroy( );
  • 加锁
    pthread_mutex_lock()
    pthread_mutex_trylock()
  • 解锁
    pthread_mutex_unlock()

3.互斥量/互斥锁 Mutex

什么是互斥量
临界区:必须以互斥方式执行的代码段,即在临界区的范围内只能有一个活动的执行线程。

  • 互斥量(Mutex),又称为互斥锁,是用来保护临界区的特殊变量,每个互斥锁内部有一个线程等待队列,保存等待该互斥锁的线程。
  • 有锁定(locked)和解锁(unlocked)状态:
  • 锁定状态,某个特定的线程正持有这个互斥锁,其他线程将阻塞在互斥锁的等待队列内;
  • 解锁状态,没有线程持有这个互斥锁,如果某个线程试图获取这个互斥锁,那么这个线程就可以得到这个互斥锁而不会阻塞。

互斥量/互斥锁 Mutex示例

请添加图片描述
运行结果如下图所示:
请添加图片描述

死锁

这里通过让两个进程不断争夺运行资源来使程序进入死锁状态。

死锁范例

请添加图片描述
运行结果如下图所示:
请添加图片描述

条件变量

  • 互斥锁用来给资源上锁,而条件变量是用来等待而不是用来上锁。
  • 条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。

注:条件变量通常和互斥锁同时使用。

条件变量示例

请添加图片描述
运行结果如下图所示:
请添加图片描述

请添加图片描述

进程

1.进程环境

程序与进程

程序(program)

  • 程序是静态的
  • 程序 = 指令序列(完成特地任务) + 数据

进程(process)

  • 是一个已经开始执行但还没有终止的程序实例。
  • 包含有进程运行环境、内存地址空间、进程ID、和至少一个被称为线程的执行控制流等资源。
  • 一个程序可以实例化为多个进程实体。
  • 进程是一个动态的实体

程序到进程转换

  • 查找命令所对应程序文件的位置;
  • 使用fork()函数为之创建一个新进程;
  • 在新进程中调用exec族函数装载程序文件,并执行程序文件的main()函数。

进程的状态

  • R:进程处于运行态或就绪状态,只有在该状态的进程才可能在CPU上运行;
  • D:不可中断的深睡眠状态,处于这种反状态的进程不能响应异步信号;
  • S:可中断的浅睡眠状态,处于这个状态的进程因为等待某种事件的发生而被挂起;
  • T:暂停状态或跟踪状态;
  • W:退出状态,进程即将被销毁;
  • Z:退出状态,进程成为僵尸进程。

进程的参数

  • 环境变量
    进程获取环境变量的3种途径:
  1. 通过main()函数的第3个参数env获取;
    main()函数的三种原型:
 int main();
 int main(int argc,char*argv[ ]);
 int main(int argc,char*argv[ ],char*env[ ]);

agrc表示命令行参数的个数;argv是指向参数的各个指针所构成的数组,env参数是指向环境变量字符串的数组
2. 通过environ全局变量获取;
3. 通过getenv()函数获取。

进程环境示例

请添加图片描述
请添加图片描述

2.进程基本操作

创建进程-fork()

  • 函数以拷贝父进程的方式创建子进程。子进程与父进程有相同的代码空间、文件描述符等资源
  • 创建后,子进程与父进程开始并发执行,执行顺序由内核调度算法来决定
  • fork()对父子进程各返回一次,
    父进程:子进程的PID;
    子进程:0;
    失败:小于0错误码。

创建进程-fork()示例

请添加图片描述

运行结果如下图所示:
请添加图片描述

终止进程

  • 正常终止
    调用类exit()函数。
    main()函数return返回,也是调用类exit()函数
  • 异常终止
    调用abort()函数实现,通过SIGABRT信号调用

被执行程序:负责打印参数个数、参数列表和环境变量

请添加图片描述
请添加图片描述

wait()函数

函数原型:pid_t wait(int *status)
status是用来保存子进程退出状态的指针

  • 帮助父进程获取其子进程的退出状态
  • 如果父进程未调用wait()函数,则子进程的退出信息将一直保存在内存中
  • 僵尸进程:子进程先终止,但父进程没有调用wait()一直占用系统资源。
  • 孤儿进程:被init进程收官,由init进程负责收集它们的退出状态

wait()函数示例

请添加图片描述
运行结果如下图所示:
请添加图片描述

守护进程

  • 后台运行的一种特殊进程,独立于控制终端,周期性地执行某种任务或等待处理某些事件
  • 守护进程属于孤儿进程,父进程变为init进程
  • Linux系统的大多数服务器就是通过守护进程实现
  • 常用daemon()创建守护进程
  • 函数原型:
int daemon(int nochdir,int noclose);

守护进程示例

请添加图片描述

3.系统信号

系统信号概念

  • 信号(signal),即软中断,用来通知进程发生了异步事件。是较为复杂的通信方式。
  • 一般方向:进程之间、内核给进程。
  • 仅通知事件类型,不传递数据

收到信号后进程的处理方式

  • 忽略
  • 系统默认(大部分的信号使得进程被终止)
  • 类似中断,进程调用预先指定的、对应的函数

信号函数

  • sigaction函数
    改变信号的处理方法,SIGKILL和SIGSTO例外。
  • Kill()函数
    向指定的进程发送一个指定的信号,成功返回0,否则返回-1。

信号函数用法示例

请添加图片描述
由于没有信号发生,因此一直在sleep,运行结果如下所示:
请添加图片描述

4.线程与进程的关系

一个线程只能是某一个进程的一部分,一个进程可以有多个线程(至少有一个主线程)

开发板

安装完开发板之后打开

$  ~/ubuntu-18.04_imx6ul_qemu_system/gui-qemu-imx6ull-gui.sh

1.LCD屏幕/图像

分别输入下列命令打开LCD屏幕和图像

$ fb-test

打开LCD屏幕
请添加图片描述

$ ./myfb-test /dev/fb0

打开图像
请添加图片描述

2.串口EEPROM

$ cd ~
$ i2cdetect -l #列出所有i2c总线
$ i2cdetect -y 0 #列出总线0上的设备

请添加图片描述
写入:

$ i2c_usr_test /dev/i2c-0 0x50 w 0x01 0xff     #w = write

注:/dev/i2c-0 是这个总线的设备夫,0x50是被操作地址,w是指改写地址内容,0x01是位置,0xff是写入的内容。
请添加图片描述
读取:

$ i2c_usr_test /dev/i2c-0 0x50 w 0x33 

读取0x33位置的内容
请添加图片描述

3.命令控制LED

打开LED控制以及安装LED驱动:

$ cd ~
$ cd led_driver_qemu/
$ insmod 100ask_led.ko

控制LED零号灯亮,LED一号灯灭:

$ ./ledtest /dev/100ask_led0 on
$ ./ledtest /dev/100ask_led1 off

请添加图片描述
请添加图片描述

4.按键控制LED

$ cd ~
$ cd button_driver_qemu/
$ insmod button_drv.ko 
$ insmod board_100ask_qemu_imx6ull.ko 

启动按钮控制:

$ ./button_led_test

请添加图片描述
可以看到1号按钮控制灯亮了,2号按钮控制灯灭了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值