一、进程与线程
什么是进程
1. 指在运行中的程序,例如使用微信就启动一个进程,操作系统就会为 该进程分配内存空间;
2. 进程是程序的一次执行的过程,或者是正在运行的一个程序;是动态过程,有它自身的产生、存在和消亡的过程
3. 进程是程序执行时的一个实例,是担当分配系统资源(CPU时间、内存等)的基本单位,还是线程的容器过程。
什么是线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
1. 线程由进程创建的,是进程的一个实体;
2. 一个进程可以拥有多个线程;
3 .单线程:同一时刻,只允许执行一个线程;
4. 多线程:同一时刻,可以执行多个线程。
并发和并行
并发:
同一时刻,多个任务交替执行;单核CPU实现的多任务就是并发
并行:
同一个时刻,多个任务同时执行,多核CPU可以实现并行
二、使用线程的理由(线程的优点):
(1) 进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。
(2) 和进程相比,它是一种非常"节俭"的多任务操作方式,运行于一个进程中的多个线程,它们彼此 之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程 所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间
(3) 线程间方便的通信机制,一个线程的数据可以直接为其它线程所用。
(4) 创建 一个新线程的代价要比创建一个新进程小得多
(5) 与进程之间的切换相比,线程之间的 切换 需要OS的工作量更少
(6) 线程占用的 资源 比进程少得多
三、线程和进程的区别:
第一种方法:
一个进程在运行的时候,要给他分配内存,要维护它的数据段和代码段以及堆栈等等,而线程是跟进程共享这些东西,开辟多个线程不会分配新的内存,和进程相比,它是一种非常"节俭"的多任务操作方式。
第二种方法:
1 .根本区别:进程是操作系统进行资源分配的最小单元,线程是操作系统进行运算调度的最小单元。
2 .从属关系不同:进程中包含了线程,线程属于进程。
3. 开销不同:进程的创建、销毁和切换的开销都远大于线程。
4 .拥有资源不同:每个进程有自己的内存和资源,一个进程中的线程会共享这些内存和资源。
5 .控制和影响能力不同:子进程无法影响父进程,而子线程可以影响父线程,如果主线程发生异常会影响其所在进程和子线程。
6 .CPU利用率不同:进程的CPU利用率较低,因为上下文切换开销较大,而线程的CPU的利用率较高,上下文的切换速度快。
7. 操纵者不同:进程的操纵者一般是操作系统,线程的操纵者一般是编程人员。
四、与线程自身相关的API
(1)pthread_create()函数:线程创建
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread_t *thread: pthread是一个指针参数,传出线程ID
const pthread_attr_t *attr: 用于指定线程属性,传入NULL表示使用默认属性
void *(*start_routine) (void *): 是个函数指针,是线程的主控函数
void *arg: 是第三个函数的参数,要强制转换成泛型(void*)然后进行值
传递即可,不能传递地址
返回值:若成功返回0,否则返回错误编号
注意:创建线程之后,有可能创建它的进程先退出了,那么;进程的存储空间将被回收,线程也就无法执行了。
(2)pthread_exit()函数:线程退出
#include <pthread.h>
void pthread_exit(void *retval);
void *retval: retval表示线程的退出值,我们必须将该参数强转为泛型void*
(3)pthread_join()函数:线程等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
pthread_t thread: thread是我们要等待退出的线程的线程ID
void **retval: retval是传出参数,用于获取线程的退出值,即,pthread_exit里的那个参数
在使用该函数时要注意retval参数:
(1) 一定要用void**强制转换为泛型指针
(2)该函数是将pthread_exit里的退出值 复制到 retval所指向的位置。
(3)该参数可以置为NULL,表示不需要获取线程退出值。
创建一个线程代码实战:
#include <stdio.h>
#include <pthread.h>
void *func1(void *arg){
static int ret = 10; //一定要加static,不加的话,线程的返回值将不知道会返回什么
printf("t1:%ld thread is create\n",(unsigned long)pthread_self()); //打印线程ID号
printf("t1:param is %d\n",*((int *)arg)); //取param参数的值
pthread_exit((void *)&ret); //线程退出
}
int main(){
int ret;
int param = 100;
pthread_t t1;
int *pret;
ret = pthread_create(&t1,NULL,func1,(void *)¶m); //创建一个线程
if(ret == 0){
printf("main:pthread_create success\n");
}
printf("mian:%ld\n",(unsigned long)pthread_self());
pthread_join(t1,(void **)&pret); //线程等待,等待线程退出的返回值传给pret
printf("main: t1 quit:%d\n",*pret);
return 0;
}
执行结果:
线程共享内存空间的代码验证:
#include <stdio.h>
#include <pthread.h>
int g_data = 0;
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg){
static int ret = 10;
printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
printf("t1:param is %d\n",*((int *)arg));
while(1){
printf("t1:%d\n",g_data++);
sleep(1);
}
pthread_exit((void *)&ret);
}
void *func2(void *arg){
static int ret = 10;
printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
printf("t2:param is %d\n",*((int *)arg));
while(1){
printf("t1:%d\n",g_data++);
sleep(1);
}
pthread_exit((void *)&ret);
}
int main(){
int ret;
int param = 100;
pthread_t t1;
pthread_t t2;
int *pret;
ret = pthread_create(&t1,NULL,func1,(void *)¶m);
if(ret == 0){
printf("main:pthread_create success\n");
}
ret = pthread_create(&t2,NULL,func1,(void *)¶m);
if(ret == 0){
printf("main:pthread_create success\n");
}
printf("mian:%ld\n",(unsigned long)pthread_self());
while(1){
printf("main:%d\n",g_data++);
sleep(1);
}
pthread_join(t1,(void **)&pret);
pthread_join(t2,(void **)&pret);
printf("main: t1 quit:%d\n",*pret);
printf("main: t2 quit:%d\n",*pret);
return 0;
}
执行结果: