C语言中的多线程简介
线程 Thread
专业术语称之为程序执行流的最小单元 。线程是不会执行程序的,可以理解成线程就是一个载体,将 要执行的代码 运送到CPU进行处理。
多线程就是多个线程同时并发执行。
(注意并发与并行的区别,并行同时执行不同的任务,并行是交替执行不同的任务。)
1,为什么要用多线程?
1)避免阻塞
单个线程中的程序,是按照顺序执行的,排在前面的程序如果发生异常卡住(阻塞),会影响到后面的程序执行。多线程就等于是异步调用,避免这个情况。
2)避免CPU的空转
这个比如一个网页,如果是单线程的话,服务器处理一条请求后,会等待下一个请求,这时候CPU处于一个闲置的状态。多线程能避免这个问题。
3)提升效率
避免了1,2的问题,效率自然就提高了,归根结底也是为了这点。
2,线程与进程的区别
进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分派的基本单位,线程只是一段程序的执行。
比如打开了一个软件(比如说QQ),能从任务管理器,就能看到有QQ这样一个进程,这时候想跟别人聊个天,打开对话框,这就是运行一个线程;查看一下聊天的这个人的资料,这又运行了另外一个线程。
同一个进程下的线程是资源共享的,进程与进程直间都是独立的。
写了几个简单程序来说明一下,怎么使用线程,线程中的问题。
---------------------------------------------------------------------------------------------------------------------------------------------------
- 创建一个线程,看 example0.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 使用线程时需要添加<pthread.h>这个头文件
// myfunc 线程携带的函数;固定为Void*型
myfunc(void* args){printf("hello world\n");return NULL;
}int main(){// 声明线程th1 pthread_t th1; pthread_create(&th1,NULL,(void*)myfunc,NULL); pthread_join(th1,NULL);
}
C语言的程序中要使用线程,需要添加<pthread.h>这个头文件
myfunc()是这个线程要携带执行的程序 ,函数与函数的参数,都是必须是 void* 类 ,涉及到调用和传值时需要进行类型强转。
主函数中,先对线程进行一个声明, pthread_t th1; 使用 pthread_create()对th1进行创建。
pthread_create()中有4个参数
1要创建的线程id(th1); 2设置线程的属性(没有特殊需求时填NULL就可以了) ; 3线程要运行的函数的地址(myfunc);4是要向运行的那个函数传参(myfunc()中的args),args 也是void*类型。
pthread_join()函数的功能是等待一个线程的结束,它是一个线程阻塞的函数。
pthread_join有两个参数:指定要等待的线程id;接收线程函数的返回值。
运行这个程序看看
如果没有pthread_join,终端可能会没有打印,因为主函数执行结束,线程中的函数还没有执行完成。
- example1.c
一个多线程的例子,来演示说明下线程的是并发执行
// 创建两个线程
void* myfunc(void* args){int i;char* name = (char*)args;for(i=1;i<50;i++){printf("%s:%d\n",name,i);}return NULL;
}int main(){pthread_t th1;pthread_t th2;pthread_create(&th1,NULL,myfunc,"th1");pthread_create(&th2,NULL,myfunc,"th2");pthread_join(th1,NULL);pthread_join(th2,NULL); }
两个线程,都去调用这个myfunc()函数,运行结果如下
从这个程序的运行结果,能看出th1运行到17时,th2开始运行了,而这时th1没有继续打印,能看出th1与th2是并发执行的。两个线程的执行顺序是不确定的,重复运行example1.c这个程序的结果也会不同。
这个程序里使用到了pthread_create()中的第四个参数向 myfunc传参。
- example3.c
int s =0;void* myfunc(void* args){int i =0;for(i=0;i<10000;i++){s++; }return NULL;
}
int main(){pthread_t th1;pthread_t th2;pthread_create(&th1,NULL,myfunc,NULL);pthread_create(&th2,NULL,myfunc,NULL);pthread_join(th1,NULL);pthread_join(th2,NULL);printf("s=%d\n",s);return 0;
}
// 用两个线程去执行myfunc函数 , 理想值应该为20000
编译后运行结果如下
这个函数里用了一个全局变量s,执行函数是一个10000的累加,理想的运行结果应该是20000,我这里运行了3次这个程序,每次的结果都不同。 用这个演示来表示一下,多线程之间是资源共享的。
s++ 是有三个步的,读取s,s+1,写入s。
在程序运行的某个时刻,th1携带myfunc执行s++,读取s,此时s=100,进行s+1, 与此同时th2也开始读取s,此时的s还是等于100, 这时th1,执行写入s=101,th2执行s++,写入s ,s=101. th2中的s 就会覆盖掉 th1中的s 。这样造成了结果的误差。
手绘感受一下,绝对记忆深刻。·
这个问题有的名字 叫 race conditon
那么怎么解决这样问题呢? 应该听过一个词, 锁
- example4.c
对example3.c中的线程进行一个加锁
int s =0;pthread_mutex_t lock; //定义一个锁void* myfunc(void* args){pthread_mutex_lock(&lock); //上锁int i =0;for(i=0;i<10000;i++){s++; }pthread_mutex_unlock(&lock);//解锁return NULL;
}
int main(){pthread_t th1;pthread_t th2;pthread_mutex_init(&lock,NULL); //初始化lock这个锁 pthread_create(&th1,NULL,myfunc,NULL);pthread_create(&th2,NULL,myfunc,NULL);pthread_join(th1,NULL);pthread_join(th2,NULL);printf("s=%d\n",s);return 0;
}
运行结果
锁的作用是什么呢?
前面说过多线程是并发执行的,th1运行后 进行了加锁,th2这时候想要运行,就必须等待th1解锁之后才行。
(一个卫生间,多个人要用,第一个人进去之后,把门锁上了,后边的人就得排队等着,第一个方便完了,解锁开门出来,第二个人进去,继续锁门……)
锁 在提高程序的安全性的同时,也降低了程序的效率。
锁的使用方法
pthread_mutex_t lock; 声明一个锁
pthread_mutex_init(&lock,NULL); 对声明的锁进行初始化
pthread_mutex_lock(&lock); //上锁 此时其他线程就开始等待
pthread_mutex_lock(&unlock); //解锁 其他线程可以使用资源了
死锁!
拿上边举例,th1运行后,th2会等待th1解锁,才能运行,如果程序出现错误中断了,th1没有执行完,重新启动后,th1又重新执行,这时候th2排在th1前边,需要等待th1的解锁 ,而th1又在等待th2结束。 这样就造成了相互等待的情况,这个就是死锁。
额外
多线程的目的
可以充分利用CPU资源,并发去做很多事,提高使用率,减少计算时间。
线程是不是越多越好?
肯定不是,要考虑线程的创建时间+销毁时间 ,选择一个适当的数量。
C语言中的多线程简介相关推荐
- c语言中全局变量多线程调用-局部变量、静态局部变量、全局变量与静态全局变量分析
基本概念: 作用域:起作用的区域,也就是可以工作的范围. 代码块:所谓代码块,就是用{}括起来的一段代码. 数据段:数据段存的是数,像全局变量就是存在数据段的 代码段:存的是程序代码,一般是只读的. ...
- 【多线程】c语言中的多线程
线程 Thread:专业术语称之为程序执行流的最小单元 .线程是不会执行程序的,可以理解成线程就是一个载体,将 要执行的代码 运送到CPU进行处理. 多线程就是多个线程同时并发执行. 1. 为什么用多 ...
- c语言中锁的作用,C语言中的多线程死锁
我是C的新手,在下面的多线程场景中,N个线程从一个二进制文件中读取,并写入自己的单独文件,例如线程1写入文件1,线程2写入文件2,等等. 这对~2/3个线程有效,但对于其他线程,它似乎陷入了死锁,但我 ...
- c语言中的多线程的实现
一.多线程的概念及程序实现 1.什么是多线程? 线程:(LWP)线程是轻量级的进程,进程是资源分配的最小单位,线程是调度的最小单位.(同一个进程下)线程共用同一个进程的资源.多线程在切换的时候要比多进 ...
- C语言中使用多线程播放游戏背景音乐
做大一下期期末设计时遇到一个问题,游戏运行时循环播放背景音乐这个情况下,如果音乐播放完毕,加入判断函数判断是否结束,如果结束则重新播放,但是在游戏中,音乐播放完毕到音乐重新开始播放中间会有一个间隙,这 ...
- Android 中的多线程简介
一.概念讲解 进程:是程序运行过程中系统进行资源分配和调度的一个独立单位,使多个程序可 并发执行,以提高系统的资源利用率和吞吐量. 线程:一个基本的CPU执行单元 & 程序执行流的最小单元. ...
- 黑科技:轻松实现JS与微信小程序中的多线程
前言 众所周知,js是单线程的去跑代码,如果使用一个较长时间的循环来执行代码,浏览器就会卡死,直到js执行完毕,用户体验极差:因此对于较长时间的代码块,最好使用多线程去执行,关于这一点网上说可以用De ...
- C语言中的转义字符【转ce123的技术博客】
C语言中的转义字符 简介 在字符集中,有一类字符具有这样的特性:当从键盘上输入这个字符时,显示器上就可以显示这个字符,即输入什么就显示什么.这类字符称为可显示字符,如a.b.c.$.+和空格符等都是可 ...
- Python:python语言中与时间有关的库函数简介、安装、使用方法之详细攻略
Python:python语言中与时间有关的库函数简介.安装.使用方法之详细攻略 目录 与时间有关的库函数 案例应用 1.打印程序块前后运行时间 #T1.采用time库
最新文章
- 后盾网lavarel视频项目---lavarel使用模型进行增删改查操作
- mysql dba系统学习(14)mysql用户管理之一、二
- Notepad++ 查找匹配中文
- 封装、继承、多态的理解
- Git 操作笔记/pip换源
- php yaf.dll,windows下配置nginx+php+yaf的环境
- 海报样机模型|让设计作品从人群中脱颖而出
- python 类继承方法_python类的继承、多继承及其常用魔术方法
- 如何在变化的时代中,抓住新时代的红利让自己跟着趋势赚钱
- 程序员都必须了解的18个Python模式程序片段
- Spring 4 Security MVC登录注销示例
- AndroidStudio插件GsonFormat快速实现JavaBean
- HDU1427 速算24点
- 【优化预测】基于matlab鲸鱼算法优化LSTM预测【含Matlab源码 105期】
- asp.net中获取远端WEB页内容
- tftp服务器的配置文件,tftp 服务器 系统配置文件
- UE5学习笔记(十一)——蓝图基础之键盘和鼠标操作移动
- 怎样用计算机画太极,用IF函数画个太极图
- Python如何利用双色球每天薅个煎饼果子
- 猫,路由器,宽带(光纤,ADSL),带宽的区别和联系