linux C 多线程编程
文章目录
- 多线程的一些小知识:
- 1创建线程 pthread_create
- 2线程挂起 pthread_join
- 3线程终止 pthread_exit
- 4线程分离 pthread_detach
- 5线程取消 pthread_cancel
- 线程同步 pthread_mutex_t互斥变量
我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能
多线程的一些小知识:
一个应用程序可以启动若干个线程。
线程(Lightweight Process,LWP),是程序执行的最小单元。
一般一个最简单的程序最少会有一个线程,就是程序本身,也就是主函数(单线程的进程可以简单的认为只有一个线程的进程)
一个线程阻塞并不会影响到另外一个线程。
多线程的进程可以尽可能的利用系统CPU资源。
1创建线程 pthread_create
先上一段在一个进程中创建一个线程的简单的代码,然后慢慢深入。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func(void * arg)
{printf("func run...\n");return NULL;
}
int main()
{pthread_t t1;int err = pthread_create(&t1,NULL,func,NULL);if(err!=0){printf("thread_create Failed:%s\n",strerror(errno));}else{printf("thread_create success\n");}sleep(1);return EXIT_SUCCESS;}
int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(start_routine)(void), void *arg);
在main函数里面我们调用上面的函数进行创建一个线程。
函数参数:
第一个参数:pthread_t代表创建线程的唯一标识,是一个结构体,需要我们创建好后,将这个结构体的指针传递过去。
第二个参数:pthread_attr_t,代表创建这个线程的一些配置,比如分配栈的大小等等。。一般我们可以填NULL,代表默认的创建线程的配置
第三个参数:代表一个函数的地址,创建线程时,会调用这个函数,函数的返回值是void*,函数的参数也是void*,一般格式就像void * func(void * arg){}
第四个参数:代表调用第三个函数传递的参数
函数返回值:
函数成功返回0,如果不等于0则代表函数调用失败,此时通过strerror(errno)可以打印出具体的错误。
注意:每个线程都拥有一份errno副本,不同的线程拥有不同的errno
最后通过gcc编译
gcc 1createthread.c -c -o 1createthread.o
gcc 1createthread.o -o thr1 -lpthread
编译的时候需要加上-lpthread 用来链接libpthread.so动态库,不然会提示找不到function
函数调用返回结果
问题:为什么调用sleep函数
答:可能新创建的线程还没运行到打印的方法主线程就结束了,而主线程结束,所有线程都会结束了。
2线程挂起 pthread_join
有时候我们在一个线程中创建了另外一个线程,主线程要等到创建的线程返回了,获取该线程的返回值后主线程才退出。这个时候就需要用到线程挂起。
int pthread_join(pthread_t th, void **thr_return);。
pthread_join函数用于挂起当前线程,直至th指定的线程终止为止。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func(void * arg)
{int i=0;for(;i<5;i++){printf("func run%d\n",i);sleep(1);}int * p = (int *)malloc(sizeof(int));*p=11;return p;}
int main()
{pthread_t t1,t2;int err = pthread_create(&t1,NULL,func,NULL);if(err!=0){printf("thread_create Failed:%s\n",strerror(errno));}else{printf("thread_create success\n");}void *p=NULL;pthread_join(t1,&p);printf("线程退出:code=%d\n",*(int*)p);return EXIT_SUCCESS;}
函数执行结果
我们主函数一直在等待创建的线程执行完,并且得到了线程执行结束的返回值
3线程终止 pthread_exit
进程终止时exit()函数,那么线程终止是什么呢?
线程终止的三种情况:
- 线程只是从启动函数中返回,返回值是线程的退出码。
- 线程可以被同一进程中的其他线程取消。
- 线程调用pthread_exit。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func(void * arg)
{int i=0;while(1){if(i==10){int * p = (int *)malloc(sizeof(int));*p=11;pthread_exit(p);}printf("fun run %d\n",i++);sleep(1);}return NULL;}
int main()
{pthread_t t1,t2;int err = pthread_create(&t1,NULL,func,NULL);if(err!=0){printf("thread_create Failed:%s\n",strerror(errno));}else{printf("thread_create success\n");}void *p=NULL;pthread_join(t1,&p);printf("线程退出:code=%d",*(int*)p);return EXIT_SUCCESS;}
void pthread_exit(void *arg);
pthread_exit函数的参数就跟正常线程结束return的使用时一样的,都会被等待它结束的主线程获取到。
函数运行结果:
4线程分离 pthread_detach
int pthread_detach(pthread_t th);
pthread_detach函数使线程处于被分离状态。
如果不等待一个线程,同时对线程的返回值不感兴趣,可以设置这个线程为被分离状态,让系统在线程退出的时候自动回收它所占用的资源。
一个线程不能自己调用pthread_detach改变自己为被分离状态,只能由其他线程调用pthread_detach。
5线程取消 pthread_cancel
int pthread_cancel(pthread_t th);
pthread_cancel函数允许一个线程取消th指定的另一个线程。
函数成功,返回0,否则返回非0。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func1(void * arg)
{while(1){printf("fun run...\n");sleep(1);}return NULL;
}
int main()
{pthread_t t1;if(pthread_create(&t1,NULL,func1,NULL)!=0){printf("thread_create Failed:%s\n",strerror(errno));return -1;}sleep(5);pthread_cancel(t1);pthread_join(t1,NULL);return EXIT_SUCCESS;}
函数执行结果:
上面我们说过创建一个线程函数pthread_create的第二个参数,用来决定创建线程的一些初始化状态,这里我们 举个例子,改线程一创建就是分离状态的线程(
上面介绍了pthread_detach函数的概念,可以通过pthread_attr_t在创建线程的时候就指定线程属性为detach,而不用创建以后再去修改线程属性。
)
先上一段代码:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func(void * arg)
{int i=0;for(;i<5;i++){printf("func run%d\n",i);sleep(1);}int * p = (int *)malloc(sizeof(int));*p=11;return p;}
int main()
{pthread_t t1;pthread_attr_t attr;//申明一个attr的结构体pthread_attr_init(&attr);//初始化结构体pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程为分离线程int err = pthread_create(&t1,&attr,func,NULL);if(err!=0){printf("thread_create Failed:%s\n",strerror(errno));}else{printf("thread_create success\n");}pthread_attr_destroy(&attr);pthread_join(t1,NULL);printf("主线程退出\n");return EXIT_SUCCESS;}
pthread_attr_t就是我们要传入的参数的结构体,一般申明的步骤有
申明一个pthread_attr_t对象
函数pthread_attr_init初始化attr结构。
设置线程的一些属性,比如pthread_attr_setdetachstate函数就是设置该线程创建的时候为正常状态还是分离状态。
函数pthread_attr_destroy释放attr内存空间
pthread_attr_setdetachstate把线程属性设置为下面两个合法值之一:
上面函数运行结果:
因为线程是个分离状态的,所以pthread_join挂起会失效,主线程很快运行结束,程序也就结束了,创建的线程还没来得及运行
线程同步 pthread_mutex_t互斥变量
有时候我们多个线程处理订单扣减库存会遇到这样的问题,两个线程同时进入一段代码先查询库存,两个都查出来为还剩一件库存,第一个线程用掉这个库存后,将库存变为0,但是第二个线程刚才也查出来为1了,所以他还认为有库存,
这个时候操作就会引发我们想不到的意外,库存变为负数了!!所以这个时候就需要使用线程的同步!!
先上一段代码看看效果:
#include<pthread.h>
#include<stdio.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>void * func(void * arg)
{int threadno =*(int*)arg;int i=0;for(;i<10;i++){printf("%d thread%d \n",threadno,i);sleep(1);}return NULL;}
int main()
{pthread_t t1,t2;int i1=1,i2=2;pthread_create(&t1,NULL,func,&i1);pthread_create(&t2,NULL,func,&i2);pthread_join(t1,NULL);pthread_join(t2,NULL);printf("主线程退出\n");return EXIT_SUCCESS;}
函数运行结果:
可以看到两个线程是没有规律的争相处理的,如果这段代码是扣减库存就完蛋啦!,所以我们要对这段代码进行加锁,同一时刻只能有一个线程进入操作!
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void * func(void * arg)
{pthread_mutex_lock(&mutex);//对mutex加锁,其他线程进入后将会挂起,知道这个锁被解锁int threadno =*(int*)arg;int i=0;for(;i<10;i++){printf("%d thread%d \n",threadno,i);sleep(1);}pthread_mutex_unlock(&mutex);return NULL;}
int main()
{pthread_t t1,t2;int i1=1,i2=2;pthread_create(&t1,NULL,func,&i1);pthread_create(&t2,NULL,func,&i2);pthread_join(t1,NULL);pthread_join(t2,NULL);printf("主线程退出\n");return EXIT_SUCCESS;}
函数运行结果:
可以看到第二个线程先进入后一直运行结束,对mutex解锁后,第一个线程才能进方法里面运行!否则会挂起,一直等到锁被解锁!
PTHREAD_MUTEX_INITIALIZER是初始化一个快速锁的宏定义。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
加锁解锁函数:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
相关文章:

JavaSE replaceAll 方法
private String srcStr "index\\.php\\?action";//要替换的原字符串 private String destStr "index.php?<{\\$LANGUAGE_TYPE}>action";//目的字符串 注意.和?都要转义,因此需要在前面添加两个反斜杠。 关于第二个参数,$…

elementui datetimepicker 移动端_在 Gitee 收获 2.5K Star,前后端分离的 RuoYi 它来了
作为 2019 年 Gitee 上最受欢迎的开源项目,权限管理系统 RuoYi 已经在 Gitee 上获得了超过 11K 的 Star。 这次作者若依推出了基于 SpringBoot Vue Element UI 的前后端分离版本的 RuoYi-Vue,方便有前后端分离开发需求的同学使用。项目名称:…

用MyEclipse开发Spring入门
1 新建一个项目 File----->New ----->Project 在出现的对话框中选择 MyEclipse 下的 Web Project,在Project Name 输入mySpring1,其他的选项默认,再点Finish完成; 2 加入Spring 包 在myspring1 项目上点右键,选…

带你轻而易举的学习python——八皇后问题
首先我们来看一下这个著名的八皇后问题 八皇后问题:在88格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 在这个问题提出之后人们又将它扩展到了nn格的棋盘摆…

ubuntu18.04.1内核升级至5.0.0-25版本
ubuntu18.04操作系统版本先已支持在线的内核版本升级,到目前为止18.04发布版已经拥有三个小版本了1,2,3。 其中18.04.01和18.04.03版本,安装好之后默认的是4.15内核版本,但是默认支持在线安装4.18和5.0.0内核版本。 具体升级步骤如下&#x…

输出n行杨辉三角数
1 /*2 输出n行杨辉三角数 3 输入n,n是1~100之间的整数 4 */5 #include<stdio.h>6 int main()7 {8 int a[100],b[100];9 int i,j; 10 int n; 11 scanf("%d",&n); 12 if(n1) 13 { 14 printf("1\…

怎么扫描_打印机上扫描仪怎么用 打印机上扫描仪使用及添加方法
打印机是生活中常用的打印设备,主要用于连接 电脑 打印电脑上的文件,方便办公。对于第一次使用打印机的朋友可能还不是很熟悉如何使用,比如打印机上 扫描仪 怎么用?怎么添加打印机扫描仪?下面小编就来为大家介绍下吧。…

java 调用webservice的各种方法总结
http://www.blogjava.net/zjhiphop/archive/2009/04/29/webservice.html 现在webservice加xml技术已经逐渐成熟,但要真正要用起来还需时日!! 由于毕业设计缘故,我看了很多关于webservice方面的知识,今天和大家一起来研究研究webservice的…

vc++图像保存,重绘
新建mfc应用程序,单文档 增加绘图 分别增加命令响应 添加成员变量UINIT 图形可以运行,如何保存呢?(一个集合类,CPtArt) 用一个类的对象来保存一个图形的三个要素 所以插入一个新的类(通常的类&a…

linux 进程内存分布及 堆分配和栈分配的特点
文章目录进程内存空间分布size命令查看内存分布堆方式内存分配和栈方式内存分配比较使用stap 深入追踪malloc逻辑进程内存空间分布 一个程序的内存空间主要如下: 代码段(text segment):只读权限;常是指用来存放程序执行代码的一块内存区域&…

echarts 坐标自适应_echarts 同一页面,多个图表 页面大小自适应
// 路径配置require.config({paths: {echarts: ./js}});// 使用require([echarts,echarts/chart/line, // 折线图echarts/chart/bar // 柱状图],function (ec) {var myChart ec.init(document.getElementByIdx_x(main));var myChartx ec.init(document.getElementByIdx_x(main…

opencv——pcb上寻找mark点(拟合椭圆的方法)
#include "stdafx.h" // FitCircle.cpp : 定义控制台应用程序的入口#include "cv.h" #include "highgui.h" #include "cxcore.h" #include "cvaux.h" #include <iostream>using namespace cv; using namespace std; v…

bit,Byte、KB、MB、GB、TB、PB、EB之间的关系
计算机存储信息的最小单位,称之为位(bit),音译比特,二进制的一个“0”或一个“1”叫一位;计算机存储容量基本单位是字节(Byte),音译为拜特,8个二进制位组成1个…

echarts 点亮中国插件研究
echarts 真的是个神奇的东西,最近做了一个需要点亮中国的移动端项目,前期就怎样点亮中国做了调研,发现微博当初炫酷的点亮效果就是用echarts做的,于是研究了一下。 一连研究了一堆demo,不管从官网还是GitHub上面&#…

linux进程间通信:无名管道 pipe
文章目录内核层实现结构通信原理特点使用函数声明使用实例单向通信双向通信编程注意事项管道中无数据时读操作会阻塞将管道的写端句柄关闭,不会影响读端数据读取管道中没有数据,写操作关闭则读操作会立即返回管道大小测试 64K管道发生写满阻塞࿰…

争吵所达到的效果要_悟空:不要害怕争吵,有时候争吵一些不喜欢的事情也能创造和谐...
悟空:八戒,你吃了早饭去把马喂了吧。八戒:好的。悟空:喂了马你去看看我们午饭可以吃什么,如果有需要提前做预备的什么事儿,你知道该怎么做吧?八戒:好的。悟空:昨天&#…

Log4j日志管理的用法
参考网址: http://www.blogjava.net/314508313/archive/2011/11/14/363653.html http://www.cnblogs.com/likwo/archive/2010/09/01/1814994.html http://fanqiang.chinaunix.net/app/other/2006-06-22/4640.shtml http://www.blogjava.net/rickhunter/articles/281…

多线程实现生产者消费者模型
首先是一个仓库接口,该接口规定的仓库大小,仓库的存取方法,如下所示 1 package pers.lan.jc.pc;2 3 /**4 * author lan [1728209643qq.com]5 * create 2018-11-27 15:596 * desc 仓库7 */8 public interface Repertory<T> {9 10 …

再记一次ceph object unfound的艰辛历程
文章目录先说问题:再说解决尝试1:尝试2(该尝试建议先在自己环境搭配对应业务测试通过后再现场尝试):感谢 学无止境996同学的陪伴和vigourtyy美丽女友的支持,直到这个解决问题的深夜先说问题: ceph 12.2.1生产环境&…

2014-01-04 SQL练习
目标数据库 250,czzznew/czzznew *关于执行计划:在PL/SQL选中查询的语句后,按下F5即可,其中Cost列表示当前操作的代价(消耗),值越大代表性能越差 t_rkxx表 (1):用2种以上方法查出xm(姓名)为test或者Test的人…

多重集表示合json数据_计数DP(划分数,多重集组合数)
划分数:把n个无区别的物品划分成不超过m组。 dp[i][j]j的i划分的总数。 dp[i[j]dp[i][j-i]dp[i-1][j] 即:将j个物品分成i份,有两种情况:每份划分都大于等于1 dp[i][j-i]; 存在有一份以上用0划分dp[i-1][j]int main(){int n,m;cin&…

搭建PHP环境遇到的问题!!
为什么80%的码农都做不了架构师?>>> 问题1: 再次./configure以下错误发生 configure: error: xml2-config not found. Please check your libxml2 installation. 解决方法: 安装libxml2 # yum install libxml2-devel 问题2&…

linux进程间通信:shell管道 | 的实现
文章目录介绍重定向函数介绍总结linux terminal输入如下命令,其中"|"符号即为我们上文中所说的无名管道介绍 正如我们上文中所描述的"|“无名管道提供了具有亲缘关系的进程之间的通信,它由于直接使用系统调用,运行效率较高。…

Golang的接口
当一只鸟走路像鸭子,游泳像鸭子,叫起来也像鸭子,那么我们就认为它就是鸭子。 Duck typing 的理念因此比喻得名。 Golang 通过 interface 实现 duck typing。 Effective Go 文章中这样描述 interface: interface 指定了一种描述对象行为的方法…

mysql 5.6.15_mysql-5.6.15-win32.zip免安装配置
此随笔是根据网上的资料整理的:环境:Windows XP系统软件来源:mysql官网下载1.下载mysql-5.6.15-win32.zip;2.解压MySQL压缩包;以下以加压到“F:\Program Files\Mysql\mysql-5.6.15-win32”为例:3.将解压目录…

jquery treeview 树形插件
jquery treeview 插件参数说明 treeview开源地址:https://github.com/jzaefferer/jquery-treeview 1、animated:String or Number 设置展开子节点时的显示速度,有 slow、normal、fast 或者指定速度值,与 jQuery 的 hide࿰…

spark调优(一)-开发调优,数据倾斜,shuffle调优
主要分为开发调优、资源调优、数据倾斜调优、shuffle调优几个部分。 开发调优和资源调优是所有Spark作业都需要注意和遵循的一些基本原则,是高性能Spark作业的基础;数据倾斜调优,主要讲解了一套完整的用来解决Spark作业数据倾斜的解决方案&am…

linux进程间通信:popen函数通过管道与shell通信
函数描述 FILE *popen(const char* command,const char* type) 该函数的执行过程如下: a. 调用pipe创建一个管道,并fork创建一个子进程来执行shell,shell会创建一个子进程来执行commad b. 将父进程的输入输出重定向到管道,建立一个单向的数据…

新的小游戏发布啦。Pop Jungle
丛林爱消除是一款画面清新,效果绚丽的消除类休闲游戏。你只需要选中尽可能多的图块,并消除它们就可以得到高分,并有无限多的关卡等待你去征服。一旦你开始玩儿你将无法停止下来,如果你还是消除星星的粉丝,那你更加不能…

mysql thread safe_Windows环境下完全手工配置Apache、MySQL和PHP(Thread Safe)
happydagui:现在LAMP(Linux、Apache、MySQL、PHP/Perl/Python的简称)已经很流行了。在Windows下也有类似的,比如 WAMP(Apache, MySQL, PHP on Windows)。这篇文章主要是介绍如何在Windows环境下完全手工配置Apache、MySQL和PHP,都是解压后直接…