1、进程
1.概念
进程是一个具有一定独立功能的程序的一次运行活动。
特点: 动态性、并发性、独立性、异步性
进程ID(PID): 标识进程的唯一数字,父进程的ID(PPID),启动进程的用户ID(UID)
2.进程互斥、同步、临界区、临界资源、临界区、死锁
互斥:进程互斥是指当有若干进程都要使用某一资源时,但该资源在同一时刻最多允许一个进程使用,这时其他进程必须等待,直到占用该资源者释放了该资源为止。
同步:一组进程按一定的顺序执行的过程称为进程间的同步.具有同步关系的这组进程称为合作进程,最为有名的是生产者和消费者进程.
临界资源:操作系统中将同一时刻只允许一个进程访问的资源称为临界资源。
临界区:进程中访问临界资源的那段程序代码称为临界区。为实现对临界资源的互斥访问,应保证诸进程互斥地进入各自的临界区。
死锁:多个进程因竞争资源而形成一种僵局,导致这些进程都无法继续往前执行。用死锁预防,死锁避免,死锁检测可以解决死锁问题。最著名的的死锁避免算法是银行家算法。
3.创建进程
函数原型: pid_t fork(); pid_t vfork();
函数功能: 拷贝一份和父进程一模一样的代码,从fork函数出开始运行。
头文件: unistd.h sys/types.h
返回值: 父进程返回自己pid,子进程返回0,创建失败返回-1
参数: 无
注意: fork和vfork都可以用于创建子进程,但是也有如下不同之处,
1. fork:子进程拥有独立的数据段,堆栈。vfork:子进程与父进程共享数据段,堆栈。
2. fork:父、子进程的执行次序不确定vfork:子进程先运行,父进程后运行,即创建一个子进程并阻塞父进程。
4.进程退出
父进程:使用return 0; 或者exit(0)退出
子进程:只能用exit(0)退出
5.进程等待
函数原型: pit_t wait(int* status)
函数功能: 阻塞调用它的进程,直到其中一个子进程结束
头文件: sys/types.h sys/wait.h
返回值: 成功-返回终止的那个子进程的pid,失败-(-1)
参数: 子进程结束的信息,不需要可以为空
6.程序执行函数
函数原型: int execl(char *pathname,const char *arg...)
函数功能: 保留原进程,运行可执行文件
头文件: unistd.h
返回值: 成功-不返回,失败-(-1)
参数: pathname为运行可自行程序的课执行程序的路径,arg以及后面一系列的参数是作为要运行文件的参数,null为结束标志
注意: fork创建一个新的进程,产生一个新的PID。exec保留原有的进程,执行新的代码。
2、线程
1.概念
概念:线程就是“轻量级”的进程。线程与创建它的进程共享代码段,数据段。线程拥有自己独立的栈。
进程和线程的区别及联系:
1、一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
2、进程是拥有资源的最小单位,线程是调度的最小单位,由于进程拥有资源,在进程调度是CPU开销较大,所以引入轻量级的线程
3、进程有独立的地址空间,而线程有自己的堆栈和局部变量,但没有单独的地址空间
4、线程执行开销小,但不利于资源的管理和保护;而进程正相反。
2.线程创建
函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
函数功能: 创建一个新的进程
头文件: pthread.h,特别注意:在编译时必须连接pthread库 即gcc -lpthread main.c -o main
返回值: 成功返回0,失败返回错误编码
参数:
thread 保存创建线程的编号,线程ID
attr 创建线程的属性,如果为空系统会给一个默认的属性,一般为NULL
start_routine 线程入口函数,线程从这个函数开始执行
arg 线程入口函数的参数,可以为NULL,一般为NULL
3.进程等待函数
函数原型: int pthread_join(pthread_t thread, void **retval)
函数功能: 当进程需要退出时,需要等待所有线程都运行结束
头文件: pthread.h,特别注意:在编译时必须连接pthread库 即gcc -lpthread main.c -o main
返回值: 成功返回0,失败返回错误编码
参数:
thread 要等待结束的线程的ID
retval 保留进程返回时的状态,一般为NULL,不保存
4.线程退出
函数原型: void pthread_exit(void *retval)
函数功能: 退出单个线程
头文件: pthread.h,特别注意:不能使用exit退出线程,否则会导致进程退出,从而所有线程都退出
返回值: 空
参数: 保存线程退出的返回值
5.线程互斥
在实际应用中,多个线程往往会访问同一数据或资源,为避免线程之间相互影响,需要引入线程互斥机制,而互斥锁(mutex)互斥机制中的一种。
1、初始化互斥锁
函数原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr)
头文件: pthread.h
返回值: 成功时返回0,失败时返回错误的编码
参数: mutex 需要初始化的互斥锁的指针,attr 指定的互斥锁的属性,一般为空
2、加锁
函数原型: int pthread_mutex_lock(pthread_mutex_t *restrict mutex)
头文件: pthread.h
返回值: 成功时返回0,失败时返回-1
参数: 需要锁住的互斥锁的指针
3、解锁
函数原型: int pthread_mutex_unlock(pthread_mutex_t *restrict mutex)
头文件: pthread.h
返回值: 成功时返回0,失败时返回-1
参数: 需要解开的互斥锁的指针
6.线程同步
同步机类似于进程中的同步,不仅需要互斥访问,而且需要按照某一顺序进行,可以使用条件变量实现同步,即 signal和 wait
初始化:
pthread_cond_t cond_ready=PTHREAD_COND_INITIALIZER;
PTHREAD_COND_INITIALIZER 为一个宏,初始值应该为0
等待条件成熟: pthread_cond_wait(&cond_ready, &mut);
参数: cond_ready 同步变量,mut 互斥变量
注意: 如果条件不满足,会解锁,然后重新加锁,所以在调用前后需要加锁和解锁
设置条件成熟: pthread_cond_signal(&cond_ready);