准备
博主:大大怪先森(记得关注,下次不要迷路哦) 编程环境:xshell(点击下载) 所示代码:码源
前言
本文将讲解多线程的基本概念!!!
提示:以下是本篇文章正文内容
一、基本概念
线程:在进程内部运行的一个执行流分支(执行流),属于进程的一部分,粒度比进程更细和更轻量化。
二、可重入函数
- main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的 时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换 到sighandler函
数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的 两步都做完之后从 sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步 之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后 向链表中插入两个节点,而最后只有一个节点真正插入链表中了。 - 像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为 不可重入函数,之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。想一下,为什么两个不的控制流程调用同一个函数,访问它的同一个局部变量或参数就不会造成错乱?
如果符合一下任意一个条件就是补课重入函数:
- 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
- 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构
三、可重入
3.1常见的不可重入的情况
- 调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的
- 调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构
- 可重入函数体内使用了静态的数据结构
3.2常见的可重入的情况
- 不使用全局变量或静态变量
- 不使用用malloc或者new开辟出的空间
- 不调用不可重入函数
- 不返回静态或全局数据,所有数据都有函数的调用者提供
- 使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数
四、volatile关键字
#include<stdio.h>
#include<string.h>
volatile int flag = 0;
void handler(int signo)
{
flag = 1;
printf("change flag 0 to 1\n");
}
int main()
{
signal(2,handler);
while(!flag);
printf("这个进程是正常退出的!\n");
return 0;
}
volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量 的任何操作,都必须在真实的内存中进行操作
五、的线程和进程
如下图: 我们会发现线程相对于我们之前所学习的进程就是多了更多的进程控制块(pcb),之前进程内部只有一个执行流,但是今天的进程却是有多个执行流,进程承担着分配资源的成本,而线程只是cpu调度的基本单位,在创建线程的过程成本是远远低于创建进程的。
5.1进程和线程
- 进程是资源分配的基本单位
- 线程是调度的基本单位
- 线程共享进程数据,但也拥有自己的一部分数据:
线程ID 一组寄存器 栈 errno 信号屏蔽字 调度优先级
进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
- 文件描述符表
- 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
- 当前工作目录
- 用户id和组id
5.2代码实现
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<pthread.h>
4 void* thread_run(void* args)
5 {
6 const char* id = (const char*) args;
7 while(1)
8 {
9 printf("I am a %s pthread.c:%d\n",id,getpid());
10 sleep(1);
11 }
12 }
13 int main()
14 {
15 pthread_t tid;
16 pthread_create(&tid,NULL,thread_run,(void*)"thread 1");
17
18 while(1)
19 {
20 printf("I am a main pthread.c,%d\n",getpid());
21 sleep(1);
22 }
23 return 0;
24 }
结果展示:
总结
希望本篇文章能给各位带来帮助,如有不足还请指正!!!
码字不易,各位大大给个收藏点赞吧!!!
宝子们,点赞,支持。 三连走一波!!!
|