Linux系统编程7--线程 写个测试脚本

Linux系统编程7–线程_写个测试脚本

  • 参考博客:

    Linux多线程编程初探 - 峰子_仰望阳光 - 博客园 (cnblogs.com)

  • 我的PC是8核*16进程,所以在固定的时间点,我可以同时运行8 * 16的进程,更多的线程(任务管理器)

    Linux线程 生产者 消费者(自学)

  • sleep不会让出系统资源,只会堵了自己的线

API

请添加图片描述

0、测试脚本

  • 实验1

    //test.sh
    ./a.out
    ./a.out
    ./a.out
    
  • >>> vim test.sh  //创建脚本 测试
    >>> chmod +x test.sh
    >>> ./test.sh
    

system("echo Hello, World!")会调用系统的命令处理程序来执行echo Hello, World!命令,从而在控制台输出"Hello, World!"。

  • 第二种
  • 实验2
//demo10.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
int g_data = 0;//都能用它pthread_mutex_t mutex;//定义锁//	int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{pthread_mutex_lock(&mutex);//加锁//pthread_self(): 获取id,输出idprintf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));//输出这个函数的参数 *argwhile(1){printf("t1:%d\n",++g_data);sleep(1);if(g_data == 3){pthread_mutex_unlock(&mutex);//解锁printf("t1 quit==============================");//pthread_exit(NULL);exit(0);  //如果是exit(0),线程崩了,整个进程也会崩}}
}void *func2(void *arg)
{printf("t2:%ld thread is creat\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));while(1){pthread_mutex_lock(&mutex);//加锁g_data++;printf("t2:%d\n",g_data);sleep(1);pthread_mutex_unlock(&mutex);//解锁}
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex,NULL);//初始化这把锁//创造线程//返回成功时,返回线程ID给t1//第二个参数定制不同线程属性//第三个参数是要开始执行的函数//第四个参数是给上面函数的参数 param = 100;ret = pthread_create(&t1, NULL, func1,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t1 success\n");}ret = pthread_create(&t2, NULL, func2,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t2 success\n");}printf("main:%ld\n",(unsigned long)pthread_self());while(1){printf("main:creat success\n");sleep(1);}pthread_join(t1,NULL); //等待t1线程退出,否则阻塞pthread_join(t2,NULL); //等待t1线程退出,否则阻塞//可以解释为什么函数中要利用 static ;不用的话,会随机给个数传过来//printf("main:t1 quit:%d\n",*pret);pthread_mutex_destroy(&mutex);//销毁这把锁return 0;
}
//test.c  测试脚本
#include <stdlib.h>
int main()
{int i = 0;for(i = 0;i<100;i++){system("./thread");}
}
>>> gcc demo10.c -o thread
>>> gcc test.c
>>> ./a.out
>>> ./a.out >>test.ret.txt & //将运行结果放在test.ret.txt文件中//& 后台运行
>>> [2] 159894       //自动显示进程
>>> kill -9 159894   //杀死进程
>>> vim test.ret.txt //看看这个文件

1、线程的创建、退出&等待

  • 基础API

  • //线程ID获取 & 比较
    #include <pthread.h>
    pthread_t pthread_self(void);
    // 返回:调用线程的ID
    
    • 对于线程ID比较,为了可移植操作,我们不能简单地把线程ID当作整数来处理,因为不同系统对线程ID的定义可能不一样。我们应该要用下边的函数:
  • #include <pthread.h>
    int pthread_equal(pthread_t tid1, pthread_t tid2);
    // 返回:若相等则返回非0值,否则返回0
    

1.1 线程创建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号int param = 100;
ret = pthread_create(&t1, NULL, func1,(void*)&param);//成功返回0,失败返回
//返回成功时,返回线程ID给t1
//第二个参数定制不同线程属性
//第三个参数是要开始执行的函数
//第四个参数是给上面函数的参数 param = 100;

1.2 线程推出

#include <pthread.h>
int pthread_exit(void *rval_ptr);
//rval_ptr是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针.pthread_exit((void *)p);//线程退出

1.3 线程等待

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号pthread_join(t1,(void **)&pret); //等待t1线程退出,否则阻塞
printf("main:t1 quit:%s\n",pret);
  • 实验
#include <stdio.h>
#include <pthread.h>//	int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{//static int ret = 10;static char *p = "t1 is run out";//pthread_self(): 获取id,输出idprintf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));//输出这个函数的参数 *arg//pthread_exit((void *)&ret);//线程退出pthread_exit((void *)p);//线程退出
}int main()
{int ret;int param = 100;pthread_t t1;//int *pret=NULL;char *pret = NULL;//创造线程ret = pthread_create(&t1, NULL, func1,(void*)&param);//成功返回0,失败返回//返回成功时,返回线程ID给t1//第二个参数定制不同线程属性//第三个参数是要开始执行的函数//第四个参数是给上面函数的参数 param = 100;if(ret == 0){printf("main:creat t1 success\n");}printf("main:%ld\n",(unsigned long)pthread_self());pthread_join(t1,(void **)&pret); //等待t1线程退出,否则阻塞//可以解释为什么函数中要利用 static ;不用的话,会随机给个数传过来//printf("main:t1 quit:%d\n",*pret);printf("main:t1 quit:%s\n",pret);return 0;
}

2、线程共享内存

  • 实验
  • 不同的线程可以共享 g_data变量
//demo4.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_data = 0;//都能用它//	int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{//pthread_self(): 获取id,输出idprintf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));//输出这个函数的参数 *argwhile(1){printf("t1:%d\n",g_data++);sleep(1);}
}void *func2(void *arg)
{printf("t2:%ld thread is creat\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));while(1){printf("t2:%d\n",g_data++);sleep(1);}
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;//创造线程				     //返回成功时,返回线程ID给t1//第二个参数定制不同线程属性    //第三个参数是要开始执行的函数//第四个参数是给上面函数的参数 param = 100;ret = pthread_create(&t1, NULL, func1,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t1 success\n");}ret = pthread_create(&t2, NULL, func2,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t2 success\n");}printf("main:%ld\n",(unsigned long)pthread_self());while(1){printf("main:creat success\n");sleep(1);}pthread_join(t1,NULL); //等待t1线程退出,否则阻塞pthread_join(t2,NULL); //等待t1线程退出,否则阻塞//可以解释为什么函数中要利用 static ;不用的话,会随机给个数传过来//printf("main:t1 quit:%d\n",*pret);return 0;
}
  • 实验结果

请添加图片描述

3、互斥锁(同步资源)

  • 互斥量 就是 一把锁;
  • 加锁—(共享资源)—解锁
  • **同步(synchronization)**是指在一定的时间内只允许某一个线程访问某个资源。而在此时间内,不允许其它的线程访问该资源。
  • 基础API

3.1 创建及销毁互斥锁

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t mutex);
// 返回:若成功返回0,否则返回错误编号pthread_mutex_init(&mutex,NULL);//初始化这把锁
pthread_mutex_destroy(&mutex);//销毁锁

3.2 加锁及解锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t mutex);
int pthread_mutex_unlock(pthread_mutex_t mutex);
// 返回:若成功返回0,否则返回错误编号pthread_mutex_lock(&mutex);//上锁 互斥量mutex
pthread_mutex_unlock(&mutex);//解锁
  • 实验
//demo8.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int g_data = 0;
//都能用它pthread_mutex_t mutex;
//被锁锁住的都叫互斥量 mutex//	int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
void *func1(void *arg)
{pthread_mutex_lock(&mutex);//上锁 互斥量mutex//pthread_self(): 获取id,输出id、printf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));//输出这个函数的参数 *argpthread_mutex_unlock(&mutex);//解锁
}void *func2(void *arg)
{pthread_mutex_lock(&mutex);//上锁printf("t2:%ld thread is creat\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));pthread_mutex_unlock(&mutex);//解锁
}void *func3(void *arg)
{pthread_mutex_lock(&mutex);//上锁printf("t3:%ld thread is creat\n",(unsigned long)pthread_self());printf("t3:param is %d\n",*((int *)arg));pthread_mutex_unlock(&mutex);//解锁
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_t t3;pthread_mutex_init(&mutex,NULL);//初始化这把锁//创造线程//返回成功时,返回线程ID给t1//第二个参数定制不同线程属性//第三个参数是要开始执行的函数//第四个参数是给上面函数的参数 param = 100;ret = pthread_create(&t1, NULL, func1,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t1 success\n");}ret = pthread_create(&t2, NULL, func2,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t2 success\n");}ret = pthread_create(&t3, NULL, func3,(void*)&param);//成功返回0,失败返回if(ret == 0){printf("main:creat t3 success\n");}printf("main:%ld\n",(unsigned long)pthread_self());pthread_join(t1,NULL); //等待t1线程退出,否则阻塞pthread_join(t2,NULL); //等待t1线程退出,否则阻塞pthread_join(t3,NULL); //等待t1线程退出,否则阻塞//可以解释为什么函数中要利用 static ;不用的话,会随机给个数传过来//printf("main:t1 quit:%d\n",*pret);pthread_mutex_destroy(&mutex);//销毁锁return 0;
}
  • 实验结果

请添加图片描述

  • t1结束后,t2和t3会进行竞争,main函数没有上锁,所以可以穿插进来;

4、互斥锁限制共享资源的访问

见文首–测试脚本demo10 [Link text][#anchor-0]

5、死锁(面试)

  • 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进

  • 造成死锁的条件

    • 有两个锁
    • 线程a获得了锁1,还想要获得锁2;
    • 线程b获得了锁2,还想要获得锁1;
    //demo7
    #include <stdio.h>
    #include <pthread.h>//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
    int g_data = 0;pthread_mutex_t mutex;
    pthread_mutex_t mutex2;void *func1(void *arg)
    {int i;pthread_mutex_lock(&mutex);sleep(1);pthread_mutex_lock(&mutex2);for(i=0;i<5;i++){printf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));sleep(1);}pthread_mutex_unlock(&mutex);}void *func2(void *arg)
    {pthread_mutex_lock(&mutex2);sleep(1);pthread_mutex_lock(&mutex);printf("t2:%ld thread is create\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));pthread_mutex_unlock(&mutex);}void *func3(void *arg)
    {pthread_mutex_lock(&mutex);printf("t3:%ld thread is create\n",(unsigned long)pthread_self());printf("t3:param is %d\n",*((int *)arg));pthread_mutex_unlock(&mutex);}int main()
    {int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_t t3;pthread_mutex_init(&mutex, NULL);pthread_mutex_init(&mutex2, NULL);ret = pthread_create(&t1, NULL, func1,(void *)&param);if(ret == 0){printf("main:create t1 success\n");}ret = pthread_create(&t2, NULL, func2,(void *)&param);if(ret == 0){printf("main:create t2 success\n");}ret = pthread_create(&t3, NULL, func3,(void *)&param);printf("main:%ld\n",(unsigned long)pthread_self());pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_mutex_destroy(&mutex);pthread_mutex_destroy(&mutex2);return 0;
    }
    

6、线程条件控制,实现线程的同步

  • 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。
  • 动态初始化和静态初始化;二选一
//动态初始化
pthread_mutex_t mutex; //定义一把锁
pthread_cond_t cond;   //定义一个条件
//main函数里面定义
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
//静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//使用了静态初始化,main函数可以不用定义pthread_mutex_init(&mutex,NULL);&& pthread_cond_init(&cond,NULL);

6.1 创建及销毁条件变量

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号pthread_cond_init(&cond,NULL);
pthread_cond_destroy(&cond);//销毁条件
  • 除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL

6.2 等待

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 返回:若成功返回0,否则返回错误编号pthread_cond_wait(&cond,&mutex);//等待条件发生
//cond:条件      mutex:锁
  • pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会生成一个代表一个出错码的返回变量。

  • 传递给pthread_cond_wait互斥量(锁) 对条件进行保护,调用者把锁住的互斥量传给函数。函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁,这两个操作都是原子操作。这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。

  • 实验

//text.c
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data = 0;
//动态初始化
pthread_mutex_t mutex;
pthread_cond_t cond;   //定义一个条件
/*
动态初始化和静态初始化;二选一
//静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//使用了静态初始化,main函数可以不用定义pthread_mutex_init(&mutex,NULL);&& pthread_cond_init(&cond,NULL);
*/
void *func1(void *arg)
{printf("t1:%ld thread is create\n",(unsigned long)pthread_self());printf("t1:param is %d\n",*((int *)arg));static int cnt = 0;while(1){pthread_cond_wait(&cond,&mutex);//等待条件发生//cond:条件      mutex:锁printf("t1 run================================\n");printf("t1:%d\n",g_data++);g_data = 0;sleep(1);if(cnt++ == 10){exit(1);//全退出,线程退出,全都死掉}}}void *func2(void *arg)
{printf("t2:%ld thread is create\n",(unsigned long)pthread_self());printf("t2:param is %d\n",*((int *)arg));//输出参赛 *argwhile(1){printf("t2: %d\n",g_data);pthread_mutex_lock(&mutex);g_data++;if(g_data==3){pthread_cond_signal(&cond);//触发,t1执行}pthread_mutex_unlock(&mutex);	sleep(1);}
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex,NULL);pthread_cond_init(&cond,NULL);ret = pthread_create(&t1, NULL, func1,(void *)&param);if(ret == 0){
//		printf("main:create t1 success\n");}ret = pthread_create(&t2, NULL, func2,(void *)&param);if(ret == 0){
//		printf("main:create t2 success\n");}//	printf("main:%ld\n",(unsigned long)pthread_self());pthread_join(t1,NULL);//等待pthread_join(t2,NULL);//等待pthread_mutex_destroy(&mutex);//销毁pthread_cond_destroy(&cond);//销毁条件return 0;
}
  • 结果

请添加图片描述

  • 输出到txt文件

请添加图片描述



欢迎大家一起交流讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/503719.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据和机器学习在气象预报中的应用-张平文院士

报告链接&#xff1a;张平文院士 -- 大数据和机器学习在气象预报中的应用_哔哩哔哩_bilibili

MATLAB R2022b 安装教程

MATLAB R2022b 安装教程 MathWorks 于2022年9月发布了 MATLAB 和 Simulink 产品系列的最新版本 Matlab R2022b版本 &#xff0c;加入两个新产品&#xff1a; Medical Imaging Toolbox — 可视化、配准、分割和标注二维及三维医学图像Simscape Battery — 设计和仿真电池和储能系…

ceph性能测试

查看集群状态 ceph -s查看osd情况 ceph osd tree创建pg_num为60的pool&#xff0c;名为test。 ceph osd pool create test 60rados bench用于测试rados存储池底层性能&#xff0c;该工具可以测试写、顺序读、随机读三种类型 rados bench -p <pool_name> <seconds&…

Linux网络编程——网络基础

Linux网络编程——网络基础 1. 网络结构模式1.1 C/S 结构1.2 B/S 结构 2. MAC 地址3. IP地址3.1 简介3.2 IP 地址编址方式 4. 端口4.1 简介4.2 端口类型 5. 网络模型5.1 OSI 七层参考模型5.2 TCP/IP 四层模型 6. 协议6.1 简介6.2 常见协议6.3 UDP 协议6.4 TCP 协议6.5 IP 协议6…

Linux中的动静态库

目录 一、静态库 &#xff08;1&#xff09;静态库的优缺点&#xff1a; &#xff08;2&#xff09;Linux下静态库的创建和执行 1.直接编译​编辑 2.指定路径和库名 3.用LIBRARY_PATH环境变量来配置路径 二、动态库 &#xff08;1&#xff09;动态库的优缺点 &#xff…

基于JAVA的生鲜超市销售系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 商品档案模块2.2 商品进货模块2.3 商品销售模块2.4 供应商模块2.5 活动管理模块2.6 消息通知模块 三、系统展示四、核心代码4.1 查询商品4.2 商品入库4.3 商品出库4.4 查询商品类型4.5 查询店铺活动 五、免责说明 一、摘…

CloudCanal x Hive 构建高效的实时数仓

简述 CloudCanal 最近对于全周期数据流动进行了初步探索&#xff0c;打通了Hive 目标端的实时同步&#xff0c;为实时数仓的构建提供了支持&#xff0c;这篇文章简要做下分享。 基于临时表的增量合并方式基于 HDFS 文件写入方式临时表统一 Schema任务级的临时表 基于临时表的…

MWC 2024丨美格智能发布全新5G-A模组及FWA解决方案,将5.5G带入现实

2月26日&#xff0c;在MWC 2024世界移动通信大会上&#xff0c;美格智能正式宣布推出5G-A模组SRM817WE以及全新的5G-A FWA解决方案&#xff0c;包含5G-A CPE解决方案SRT858M、5G-A MiFi解决方案SRT878H和5G-A ODU解决方案SRT853MX&#xff0c;旨在进一步提升网络性能&#xff0…

持安科技孙维伯:零信任在攻防演练下的最佳实践|DISCConf 2023

近日&#xff0c;在2023数字身份安全技术大会上&#xff0c;持安科技联合创始人孙维伯应主办方的特别邀请&#xff0c;发表了主题为“零信任在攻防演练下的最佳实践”的演讲。 孙维伯在2023数字身份安全技术大会上发表演讲 以下为本次演讲实录&#xff1a; 我是持安科技的联合…

网络卡顿是怎么回事?

网络卡顿是指在网络通信过程中&#xff0c;数据传输出现延迟或中断&#xff0c;导致用户在使用网络时出现卡顿、延迟或不流畅的情况。例如&#xff1a;系统响应时间长&#xff0c;网页加载速度慢&#xff1b;视频或游戏掉帧&#xff0c;导致画面卡顿或不流畅&#xff1b;音视频…

基于springboot+vue的公寓报修管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

springboot+vue+mysql项目使用的常用注解

实体类常用注解 Data Data 是一个 Lombok 提供的注解&#xff0c;使用 Data 注解可以简化代码&#xff0c;使代码更加简洁易读。 作用&#xff1a;自动为类生成常用的方法&#xff0c;包括 getter、setter、equals、hashCode 和 toString 等需要加Lombok的依赖 <depende…