线程 进程 开发板

一、线程

1.线程创建

在传统Unix进程模型中,每个进程只有一个控制线程。在POSIX线程(pthread)的情况下,程序开始运行时,它也是以单进程中的单个控制线程启动的。在创建多个控制线程以前,程序的行为与传统的进程并没有什么区别。新增的线程可以通过调用pthread_create函数创建。函数原型:watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_18,color_FFFFFF,t_70,g_se,x_16pthread_t* tid  :  使传入的tid实参获取线程id. 后续通过这个tid操作线程.(线程的操作句柄)

pthread_attr_t* atrr  :  用于设置线程属性,通常置NULL.

void*(*start_routine)(void* arg) :  线程入口函数,线程要进行的函数.

void* arg: 传递给线程入口函数的参数(若要传多个参数, 可以组成一个结构体把结构体传入.)

返回值: 成功返回0  ,  失败返回非零值.

实现:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

运行

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16


2.线程的终止

函数原型:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_9,color_FFFFFF,t_70,g_se,x_16

实现

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

运行程序:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

这里使用pthread_create创建了五个进程并显示出来,之后又用pthread_exit来终止线程。


3.线程的连接

函数原型:

int pthread_join( 

pthread_t tid, //需要等待的线程,指定的线程必须位于当前的进程中,而且不得是分离线程

void **status //线程tid所执行的函数返回值(返回值地址需要保证有效),其中status可以为NULL );

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 运行

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16


4.线程管理

线程的初始化:

int pthread_attr_init(pthread_attr_t *attr);

线程的销毁:

int pthread_attr_destroy(pthread_attr_t *attr);

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16


5.互斥量、互斥锁

使用互斥量前要先初始化,也就是上面线程管理的内容。

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

对互斥量进行加锁和解锁的函数:

 

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex); 

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

运行watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

死锁

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

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 运行:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

因为进入了死锁状态,所以不能继续操作了,这里使用了ctrl+z退出死锁状态。

条件变量

条件变量相关的函数或者操作:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER /*静态初始化cond */ pthread_cond_init(pthread_cond_t xcond,pthread_condattr_t xcond_attr); /x动态态初始化 / /条件等待,一直等待/ int pthread_cond_uait(pthread_cond_t cond,pthread_mutex_t kmutex); /大条件等待,等待一段时间/ int pthread_cond_timewait(pthread_cond_t xcond,pthread_mutex kmutex,const timespecabstime); /发送唤醒到一个条件变量队列等待的线程/ int pthread_cond_signal(pthread_cond_t xcond); /发送唤醒到所有在条件变量队列等待的线程/ int pthread_cond_broadcast(pthread_cond_t xcond); int pthread_cond_destroy(pthread_cond_t xcond); /销毁条件变量/ static pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZE static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER; 线程A:等待条件成立 pthread_mutex_lock(&g_tMutex); pthread_cond_wait(&g_tConVar, &g_tMutex);. do_something( ) /操作临界资源/ pthread_mutex_unlock(&g_tMutex); 线程B:唤醒等待g_tConVar的线程 pthread_cond_signal(&g_tConVar);

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16 

运行

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 这里不断读取120次满足条件后才会使线程运行。


二、进程

获取环境变量

进程的参数

环境变量

进程获取环境变量的3种途径:

1)通过main()函数的第3个参数env获取; Main ()函数的三种原型: int main(); int main(int argc, char *argvO); int main(int argc, char *argv[], char *env); argc表明命令行参数的个数;argv是指向参数的各个指针所构成的数组, env参数是指向环境变量字符串的数组

2)通过environ全局变量获取;

3)通过getenv()函数获取。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_12,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_12,color_FFFFFF,t_70,g_se,x_16 创建进程

函数以拷贝父进程的方式创建子进程。子进程与父进程有相同的代码空间、文件描述符等资源

创建后,子进程与父进程开始并发执行,执行顺序由内核调度算法来决定

fork()对父子进程各返回一次, 父进程:子进程的PID, 子进程:0; 失败: 小于0;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16运行:

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 这里就打印出来了父进程和子进程的pid。

使用进程创建新程序

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

使用子进程加载新程序

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 


三、开发板

1.打开开发板:

$ ~/ubuntu18.04_imx6ul_qemu_system/gui-qemu-imx6ull-gui.sh

等待它配置完成

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

2.打开LCD图像和屏幕:

$ fb-test

$ cd myfb-test

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

$ ./myfb-test /dev/fb0

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

 3.串口EEPROM

$ cd

$ i2cdetect -l #列出所有ic2总线

$ i2cdetect -y 0 #列出总线0上的设备

UU:有设备,有内核驱动

地址:有设备,无驱动

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

这里要选择是否继续,是因为这样列出可能会使数据损坏,但这里是实验,所以就选择是。

在显示出来的矩阵中,最左边一列是十位,最上面一行是个位。

由于那些没有数字的现在是没有驱动的,但我们可以使用i2c_usr_test来绕过驱动。

对总线进行写入:

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

解释: /dev/i2c-0 是这个总线的设备符,0x50是被操作的地址,w表示对地址进行写,0x01是位置,0xff是我们想写入的内容。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

这里我又在位置33追加输入了dd。

读取:

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

因为只是读取,所以就不需要后面的内容了,这里我们读取位置33的内容。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_15,color_FFFFFF,t_70,g_se,x_16

当我们写入的时候,在仿真图上是红色,而当读的时候是绿色的。

4.命令控制LED

打开LED控制、安装LED驱动:

$ cd

$ cd led_driver_qemu/

$ insmod 100ask_led.ko

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

$ ./ledtest /dev/100ask_led0 on

$ ./ledtest /dev/100ask_led1 off

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_16,color_FFFFFF,t_70,g_se,x_16

 

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_12,color_FFFFFF,t_70,g_se,x_16

 5.按键控制LED

安装驱动:

$ cd

$ cd button_driver_qemu/

$ insmod button_drv.ko #扫描你的按键

$ insmod board_100ask_qemu_imx6ull.ko 

启动按键控制:

$ ./button_led_test

之后你就可以通过虚拟的按键来控制LED灯的亮灭了。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQXVnZW5zdGVybsK3S1VO,size_20,color_FFFFFF,t_70,g_se,x_16 

退出就直接按ctrl+z。

GIT

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值