进程是资源分配的最小单位,线程是CPU调度的最小单位
进程有自己的独立地址空间,线程共享进程中的地址空间
进程的创建消耗资源大,线程的创建相对较小
进程的切换开销大,线程的切换开销相对较小
进程:程序执行的过程叫进程。
线程:进程内部的一条执行序列或执行路径,一个进程可以包含多条线程(多线程)!
每个进程最少有一个线程,例如下面代码:
#include <stdio.h> int main() { return 0; }
虽然只有一个主函数main,主函数的线程又叫主线程,其他的线程都叫它的子线程
下面来认识一下创建线程,退出线程,等待线程这些函数所需的参数以及具体是什么意义
线程的创建:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 12. void *(*start_routine) (void *), void *arg) //里面有四个参数 //pthread_t *thread: 接收创建的线程的ID //attr: 指定线程的属性 一般为NULL //void *(start_routine)(void *): 其中start_routine指定线程函数 然后前面那个void*就是函数的返回值是void *的,后面括号里的void *就是这个函数的参数是void *类型 //arg: 给线程函数传递的参数(如果上面那个线程函数的参数是void *的话,这块填NULL就好)
线程的等待函数:
int pthread_join(pthread_t thread, void **retval); //pthread_join()等待thread指定的线程退出,线程未退出时,该方法阻塞 //retval:接收thread线程退出时,指定的退出信息(这块如果没有特殊的返回信息,写NULL就好)
线程的退出函数:
int pthread_exit(void *retval); //retval:指定退出信息
然后下面来写一个简单的代码来实现一下多线程:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<pthread.h> //多线程的创建 等待 退出所需的头文件 void* fun(void* arg) //线程函数 { for(int i = 0 ; i < 3 ; i++) { printf("fun run!\n"); } } int main() { pthread_t id; //线程id pthread_create(&id,NULL,fun,NULL); //线程的创建 for(int i = 0 ; i < 3 ; i++) { printf("main run"); } }
上述程序的结果应该是main run和fun run各打印三次 但是结果不尽人意,如下图:
结果是子线程没有执行,只有主线程,这块就得提一下子线程和主线程的执行顺序----> 并发执行
下面来看一张照片:
来自于《Linux高性能服务器编程》上的一张照片,上面说了,多线程并发是看起来像“并发”,其实是cpu以时间片作为周期来切换线程来执行,也就是说,在上述代码执行的时候,是主线程在第一个时间片内先抢到了cpu资源,先执行的主线程,然后在第一个时间片内,主线程结束了,进程也就结束了,当然子线程也就不会打印了,这时候上面说到的线程等待函数就派上用场了
还有一位大哥在博客中写的很好,很清楚:
多线程(并发执行)_Bella_chene的博客-CSDN博客_多线程执行
来看下面代码:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<pthread.h> //多线程的创建 等待 退出所需的头文件 void* fun(void* arg) //线程函数 { for(int i = 0 ; i < 3 ; i++) { printf("fun run!\n"); } } int main() { pthread_t id; //线程id pthread_create(&id,NULL,fun,NULL); //线程的创建 for(int i = 0 ; i < 3 ; i++) { printf("main run"); } pthread_join(id,NULL); //id就是指定的线程id 这块的id就是子线程的线程id //这块的NULL是在子线程中没有用篇thread_exit()返回的值 }
加上等待函数pthread_join()之后的运行结果也印证了上述时间片的那个说法:
在第一个时间片内,主函数执行完,之后本来是要结束进程的,但是pthread_join函数这块传入的是子线程的线程id,必须等子线程执行完之后,他才可以结束,要不就储于阻塞状态!
然后还有一个线程退出函数,下面来介绍一下:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<pthread.h> //多线程的创建 等待 退出所需的头文件 void* fun(void* arg) //线程函数 { for(int i = 0 ; i < 3 ; i++) { printf("fun run!\n"); } pthread_exit("fun run over");//这块返回fun run over } int main() { pthread_t id; //线程id pthread_create(&id,NULL,fun,NULL); //线程的创建 for(int i = 0 ; i < 3 ; i++) { printf("main run"); } char * s= NULL; //将pthread_exit返回的值存储于s中 pthread_join(id,(void**)&s); //id就是指定的线程id 这块的id就是子线程的线程id //(void**)&s用来接收线程推出的值 printf("%s\n",s); }
附上运行结果:
pthread_exit()函数的返回值打印在了最后!
这样的话,基本的Linux的多线程基础基本就没了,后面会陆续更新多线程用信号量控制,用互斥锁控制!