一、线程
1.线程创建
在传统Unix进程模型中,每个进程只有一个控制线程。在POSIX线程(pthread)的情况下,程序开始运行时,它也是以单进程中的单个控制线程启动的。在创建多个控制线程以前,程序的行为与传统的进程并没有什么区别。新增的线程可以通过调用pthread_create函数创建。函数原型:pthread_t* tid : 使传入的tid实参获取线程id. 后续通过这个tid操作线程.(线程的操作句柄)
pthread_attr_t* atrr : 用于设置线程属性,通常置NULL.
void*(*start_routine)(void* arg) : 线程入口函数,线程要进行的函数.
void* arg: 传递给线程入口函数的参数(若要传多个参数, 可以组成一个结构体把结构体传入.)
返回值: 成功返回0 , 失败返回非零值.
实现:
运行
2.线程的终止
函数原型:
实现
运行程序:
这里使用pthread_create创建了五个进程并显示出来,之后又用pthread_exit来终止线程。
3.线程的连接
函数原型:
int pthread_join(
pthread_t tid, //需要等待的线程,指定的线程必须位于当前的进程中,而且不得是分离线程
void **status //线程tid所执行的函数返回值(返回值地址需要保证有效),其中status可以为NULL );
运行
4.线程管理
线程的初始化:
int pthread_attr_init(pthread_attr_t *attr);
线程的销毁:
int pthread_attr_destroy(pthread_attr_t *attr);
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);
运行
死锁
这里通过让两个进程不断争夺运行资源来使程序进入死锁状态。
运行:
因为进入了死锁状态,所以不能继续操作了,这里使用了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);
运行
这里不断读取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()函数获取。
创建进程
函数以拷贝父进程的方式创建子进程。子进程与父进程有相同的代码空间、文件描述符等资源
创建后,子进程与父进程开始并发执行,执行顺序由内核调度算法来决定
fork()对父子进程各返回一次, 父进程:子进程的PID, 子进程:0; 失败: 小于0;
运行:
这里就打印出来了父进程和子进程的pid。
使用进程创建新程序
使用子进程加载新程序
三、开发板
1.打开开发板:
$ ~/ubuntu18.04_imx6ul_qemu_system/gui-qemu-imx6ull-gui.sh
等待它配置完成
2.打开LCD图像和屏幕:
$ fb-test
$ cd myfb-test
$ ./myfb-test /dev/fb0
3.串口EEPROM
$ cd
$ i2cdetect -l #列出所有ic2总线
$ i2cdetect -y 0 #列出总线0上的设备
UU:有设备,有内核驱动
地址:有设备,无驱动
这里要选择是否继续,是因为这样列出可能会使数据损坏,但这里是实验,所以就选择是。
在显示出来的矩阵中,最左边一列是十位,最上面一行是个位。
由于那些没有数字的现在是没有驱动的,但我们可以使用i2c_usr_test来绕过驱动。
对总线进行写入:
$ i2c_usr_test /dev/i2c-0 0x50 w 0x01 0xff #w = write
解释: /dev/i2c-0 是这个总线的设备符,0x50是被操作的地址,w表示对地址进行写,0x01是位置,0xff是我们想写入的内容。
这里我又在位置33追加输入了dd。
读取:
$ i2c_usr_test /dev/i2c-0 0x50 w 0x33
因为只是读取,所以就不需要后面的内容了,这里我们读取位置33的内容。
当我们写入的时候,在仿真图上是红色,而当读的时候是绿色的。
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
5.按键控制LED
安装驱动:
$ cd
$ cd button_driver_qemu/
$ insmod button_drv.ko #扫描你的按键
$ insmod board_100ask_qemu_imx6ull.ko
启动按键控制:
$ ./button_led_test
之后你就可以通过虚拟的按键来控制LED灯的亮灭了。
退出就直接按ctrl+z。
GIT