通信原理课设(gec6818) 005:进程
进程的概念很重要,在后续编写大工程时,有很多地方都需要开辟线程,先来了解进程和线程的概念。
1、概念
上一期的触摸屏,我们知道一般触摸屏是一个死循环,它的操作一般是不会受其他的程序的影响,这个时候需求系统能同时执行多个指令,也就是说进入死循环之后,我们还能执行其他的指令。(比如后期在做音乐播放器时,就需要在实现触摸屏功能的同时,也能播放音乐)
在此之前我们还需要了解并行和并发的区别:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。 并发是逻辑上的同时发生(simultaneous),一个处理器同时处理多个任务。
由于cpu的核心是有限的,没有办法同时执行这么多条指令。但是cpu的速度是非常快的,它执行一条指令的时间非常短,我们在一个非常短的时间之内进行快速切换,外界的人看起来就像是在并行 ,实际上是并发。
并发将我们的进程分为三个状态
1 就绪态
2 运行态
3 阻塞态
这三个状态在快速的切换,进程一直在轮询,这么一来,外界看起来这个cpu就像是在同时执行很多个指令。
系统一般分为实时系统与分时系统:
分时系统 --- 基于时间片的调度
实时系统 --- 中断
并发就是基于时间片的调度。
进程:就是运行起来的这个程序,系统是基于这个进程分配资源的, 每一个进程分配到的资源都是独立的,他们之间是互不影响 --- 他们之间的通信必须要借助系统/网络。
线程:基于进程,属于进程里面的一个并发分支。一个进程里面的多个线程都是共享进程的内存空间,因此他们之间的通信就很简单,一个全局变量即可 ,并且cpu是基于线程进行调度的。
有了进程以后,可以让操作系统从宏观层面实现多应用并发。而并发的实现是通过 CPU 时间片不断切换执行的。对于单核 CPU 来说,在任意一个时刻只会有一个进程在被CPU 调度。
2、函数
有了线程之后,我们就能在宏观层面实现多应用并发。以下是一些常用的进程函数
i.创建线程
线程在系统里面开始的时候是不存在的
我们想用这个线程,我们首先要开辟出这个线程 --- 创建线程
pthread_create - create a new thread
SYNOPSIS
#include <pthread.h>
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
参数解释:
thread:用来保存线程的id,后面只要这个线程不死,我们就可以通过这个id来找到这个线程。
attr: 线程的属性,一般我们都是给NULL,表示采用默认属性
start_routine:函数指针,指向你要执行的任务 也就是我们所谓的任务函数,函数的原型: void * functionname(void * arg) {}
arg: 为了搞定上面的线程函数的传参问题
返回值:成功返回0,失败返回-1,同时errno被设置
示例:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void * func(void * arg)
{
int * flag = (int *)arg;
while(1)
{
printf("func %d\n",*flag);
sleep(1);
}
}
int main()
{
//开辟一个线程让它去跑
pthread_t thread;
int flag = 1024;
if(pthread_create(&thread,NULL,func,&flag) != 0)
{
perror("pthread create error");
return -1;
}
while(1)
{
printf("main\n");
sleep(1);
}
return 0;
}
不开辟线程的情况下,主函数进入while(1)后,终端只会打印"main",但由于我们开辟了线程,所以终端能打印"main"、"func 1024",如图所示:
注意,我们要用线程,必须要用这个库pthread。也就是终端进行编译时,必须-lpthread
gcc main.c -o main -lpthread
ii 进程死亡
线程也是需求资源的,默认的情况下面,线程死亡的时候这些资源是不会回收的,我们需要回收这个线程,如果不回收就会成为僵尸线程 -- 占用资源又不做事情。
方式一:等待线程死亡
NAME
pthread_join - join with a terminated thread
SYNOPSIS
#include <pthread.h>
int pthread_join(
pthread_t thread,
void **retval);
方式二:分离模式
NAME
pthread_detach - detach a thread
SYNOPSIS
#include <pthread.h>
int pthread_detach(pthread_t thread);
方式三:分离模式进阶(自己分离自己)推荐
分离自己首先要获取自己线程的id,用pthread_self
NAME
pthread_self - obtain ID of the calling thread
所以自己分离自己
pthread_detach(pthread_self());//自己分离自己
一般我们一来就分离自己,也就是在线程函数的最开始就分离自己。