线程 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语言中的多线程简介相关推荐

  1. c语言中全局变量多线程调用-局部变量、静态局部变量、全局变量与静态全局变量分析

    基本概念: 作用域:起作用的区域,也就是可以工作的范围. 代码块:所谓代码块,就是用{}括起来的一段代码. 数据段:数据段存的是数,像全局变量就是存在数据段的 代码段:存的是程序代码,一般是只读的. ...

  2. 【多线程】c语言中的多线程

    线程 Thread:专业术语称之为程序执行流的最小单元 .线程是不会执行程序的,可以理解成线程就是一个载体,将 要执行的代码 运送到CPU进行处理. 多线程就是多个线程同时并发执行. 1. 为什么用多 ...

  3. c语言中锁的作用,C语言中的多线程死锁

    我是C的新手,在下面的多线程场景中,N个线程从一个二进制文件中读取,并写入自己的单独文件,例如线程1写入文件1,线程2写入文件2,等等. 这对~2/3个线程有效,但对于其他线程,它似乎陷入了死锁,但我 ...

  4. c语言中的多线程的实现

    一.多线程的概念及程序实现 1.什么是多线程? 线程:(LWP)线程是轻量级的进程,进程是资源分配的最小单位,线程是调度的最小单位.(同一个进程下)线程共用同一个进程的资源.多线程在切换的时候要比多进 ...

  5. C语言中使用多线程播放游戏背景音乐

    做大一下期期末设计时遇到一个问题,游戏运行时循环播放背景音乐这个情况下,如果音乐播放完毕,加入判断函数判断是否结束,如果结束则重新播放,但是在游戏中,音乐播放完毕到音乐重新开始播放中间会有一个间隙,这 ...

  6. Android 中的多线程简介

    一.概念讲解 进程:是程序运行过程中系统进行资源分配和调度的一个独立单位,使多个程序可 并发执行,以提高系统的资源利用率和吞吐量. 线程:一个基本的CPU执行单元 & 程序执行流的最小单元. ...

  7. 黑科技:轻松实现JS与微信小程序中的多线程

    前言 众所周知,js是单线程的去跑代码,如果使用一个较长时间的循环来执行代码,浏览器就会卡死,直到js执行完毕,用户体验极差:因此对于较长时间的代码块,最好使用多线程去执行,关于这一点网上说可以用De ...

  8. C语言中的转义字符【转ce123的技术博客】

    C语言中的转义字符 简介 在字符集中,有一类字符具有这样的特性:当从键盘上输入这个字符时,显示器上就可以显示这个字符,即输入什么就显示什么.这类字符称为可显示字符,如a.b.c.$.+和空格符等都是可 ...

  9. Python:python语言中与时间有关的库函数简介、安装、使用方法之详细攻略

    Python:python语言中与时间有关的库函数简介.安装.使用方法之详细攻略 目录 与时间有关的库函数 案例应用 1.打印程序块前后运行时间 #T1.采用time库

最新文章

  1. 后盾网lavarel视频项目---lavarel使用模型进行增删改查操作
  2. mysql dba系统学习(14)mysql用户管理之一、二
  3. Notepad++ 查找匹配中文
  4. 封装、继承、多态的理解
  5. Git 操作笔记/pip换源
  6. php yaf.dll,windows下配置nginx+php+yaf的环境
  7. 海报样机模型|让设计作品从人群中脱颖而出
  8. python 类继承方法_python类的继承、多继承及其常用魔术方法
  9. 如何在变化的时代中,抓住新时代的红利让自己跟着趋势赚钱
  10. 程序员都必须了解的18个Python模式程序片段
  11. Spring 4 Security MVC登录注销示例
  12. AndroidStudio插件GsonFormat快速实现JavaBean
  13. HDU1427 速算24点
  14. 【优化预测】基于matlab鲸鱼算法优化LSTM预测【含Matlab源码 105期】
  15. asp.net中获取远端WEB页内容
  16. tftp服务器的配置文件,tftp 服务器 系统配置文件
  17. UE5学习笔记(十一)——蓝图基础之键盘和鼠标操作移动
  18. 怎样用计算机画太极,用IF函数画个太极图
  19. Python如何利用双色球每天薅个煎饼果子
  20. 猫,路由器,宽带(光纤,ADSL),带宽的区别和联系

热门文章

  1. 一个用来学习CoAP协议的小例子
  2. go语言生成ssl证书
  3. JAVA1年经验技术栈列表
  4. wiki php markdown,一款支持Markdown语法的Wiki知识管理系统:Wikitten搭建教程
  5. 前端获取页面的高度/宽度
  6. abaqus二次开发简单插件
  7. 简约个人简历自我介绍
  8. 如何在 Ubuntu 20.04 上安装 Google Chrome 网络浏览器
  9. sql语句select中直接替换或去掉字符
  10. 高等数学(第七版)同济大学 习题7-1 个人解答