linux线程的基本知识
这里用的是Linux的pthread线程库,需要加pthread线程库。
线程的创建

第一个参数是线程id的地址。第二个参数是线程属性,一般为NULL。第三个是要执行的函数。第四个是函数的参数,一般也为NULL
线程的等待,第一个参数是线程的id,第二个一般为NULL,表示不关心退出的状态。如果主线程不等待join的话,那main函数就直接退出了。


线程的非正常终止

第一个情况就是没有join函数的效果。主线程退出子线程就终止了,这就是和进程不一样的地方。
第二个就是如果子线程溢出(比如delete内存两次),整个进程终止。
这些都是说明线程健壮性不够进程好。子线程会影响整个进程。
怎么让线程正常终止?
线程可以简单的从线程函数中返回,返回值是线程的退出码。
子线程可以return 0,或者return (void*) 1返回。因为子线程要求返回的是void() 。 0代表的就是空。
子线程可以被同一进程的其他线程用**pthread_cancel(thid)取消
子线程可以调用pthread_exit(0或void 1)**取消。
那么return 0和pthread_exit(0)区别是:如果子线程主函数又调用其他函数,在其他函数用return 0只会终止其他函数,子线程不会终止;而pthread_exit(0)线程也会终止。
线程参数的传递
1.创建的多个线程并不知道哪个线程先运行;
2.由于1,导致全局变量不能作为子线程的参数。在多进程中,全局变量可以
使用不用传递参数。
所以应该用第四个参数来给线程传递参数。比如全局变量var,第四个参数是
&var,这样是不对的。应该直接传var的值,然后强制转换成(void *) var。
这种传递参数的方法有价值吗?有,具体应用场景看后面,
上面只能传一个参数,如何传多个参数?
传地址参数。但是要保证给每个线程传一个地址,不能给多个线程传一个地址。

注意在线程主函数中把申请的内存释放掉。
这也不是一个好办法,正确的是把多个参数放在结构体中,把结构体地址传进去就可以,
线程的退出状态
和传参数一样的。在join中第二个参数传递。具体的再学习一下?
线程资源的回收
回顾一下进程资源的回收:子进程退出向父进程发送sigchild信号。父进程不处理这个信号就会产生僵尸进程。
如何避免产生僵尸进程:1、程序中显示的调用signal(SIGCHLD, SIG_IGN)来忽略SIGCHLD信号,这样子进程结束后,由内核来wai和释放资源
2、 fork两次,第一次fork的子进程在fork完成后直接退出,这样第二次fork得到的子进程就没有爸爸了,它会自动被老祖宗init收养,init会负责释放它的资源,这样就不会有“僵尸”产生了
3、一般使用信号的方式来处理,在收到SIGCHLD信号的时候,在信号处理函数中调用wait操作来释放他们的资源。
线程分离

子线程退出时,没有释放全部资源。

线程同步
互斥锁:
先声明互斥锁:pthread_mutex_t mutex;
初始化: pthread_mutex_init(&mutex,NULL)
加锁 pthread_mutex_lock(&mutex); 会阻塞等待
临界区
解锁 pthread_mutex_unlock(&mutex);
释放锁:pthread_mutex_destroy(&mutex);
互斥锁加锁失败后,会从用户态陷入到内核态,让内核帮助我们切换线程,虽然简化了使用锁的难度,但是存在一定的性能开销成本。
性能开销成本:两次线程上下文切换的成本。
1、当线程加锁失败时,内核将线程的状态从【运行】切换到睡眠状态,然后把CPU切换给其他线程运行;
2、当锁被释放时,之前睡眠状态的线程会变成就绪状态,然后内核就会在合适的时间把CPU切换给该线程运行;
自旋锁:主要用于等待时间很短的场景。
自旋锁通过CPU提供的CAS,在用户态完成加锁和解锁操作,不会主动产生线程上下文切换,所以相比互斥锁来说,会快一些开销小一些。使用自旋锁的时候,当发生多线程竞争锁的情况,加锁失败的线程会忙等待,直到拿到锁。忙等待可以通过while循环实现,不过最好是使用CPU提供的PAUSE指令来实现。
声明锁:pthread_spinlock_t mutex;
初始化:int pthread_spin_init();
int pthread_spin_lock();
读写锁
允许更高的并发性。写锁只能加到不加锁的代码,读锁只能加到读锁上。
时候读远大于写的场景,不会阻塞并发读。在linux优先考虑读锁,有可能导致写入线程饿死的情况。
条件变量
与互斥锁一起使用。实现生产消费者模型。
用互斥锁+条件变量实现生产消费者模型
pthread_cond_wait(&cond,&mutex)
这个函数的步骤
1.把互斥锁解锁;2阻塞,等待条件(被唤醒);3、条件被触发+给互斥锁加锁。
声明一个结构体缓存队列的消息
struct message
{
int id;
char mes[1000];
}
vector vm;
声明并初始化条件变量和互斥锁
void in(int sig); 数据入队
void* out(void *arg); 数据出队
int main()
{
signal(15,in); 接收15的信号,调用生产者函数;
pthread_t thid1,thid2,thid3; 创建三个消费线程;
pthread_create(&thid1,NULL,out,NULL);
}
void in(int sig)
{static int mesgid=1; //消息计数器struct message m;memset(&m,0,sizeof(message);给缓存队列加锁;生产数据; m.mesgid=mesgid++; vm.push_back(m);给缓存队列解锁;pthread_cond_broadcast(&cond); 发送条件信号,激活全部线程
}void* out(void *arg)
{struct message m; //用于存放出队的消息;while(true){给缓存队列加锁;while(vm.size()==0){pthread_cond_wait(&cond,&mutex);如果队列为空,释放锁,等待信号。while可以防止虚假唤醒。}从缓存队列取第一条记录,删除该记录memcpy(&m,&vm[0],sizeof(struct message));vm.erase(vm.begin());给缓存队列解锁;业务处理代码;}}
开发多线程的服务端程序
目的:实现多个客户端交换信息的简单聊天程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>#define BUF_SIZE 100
#define MAX_COUNT 256void* handleClient(void* arg);
void sendMsg(char* msg, int len);
void errorHandling(const char* msg);int clientCount = 0;
int clientSocks[MAX_COUNT];
pthread_mutex_t mutex;int main(int argc, char* argv[])
{int servSock, clientSock;struct sockaddr_in servAddr, clientAddr;int clientAddrSize;pthread_t threadID;if(2 != argc){printf("Usage: %s <port>\n", argv[0]);exit(1);}pthread_mutex_init(&mutex, NULL);servSock = socket(PF_INET, SOCK_STREAM, 0);if(-1 == servSock)errorHandling("socket() error!");memset(&servAddr, 0, sizeof(servAddr));servAddr.sin_family = AF_INET;servAddr.sin_addr.s_addr = htonl(INADDR_ANY);servAddr.sin_port = htons(atoi(argv[1]));if(-1 == bind(servSock, (struct sockaddr*)&servAddr, sizeof(servAddr)))errorHandling("bind() error!");if(-1 == listen(servSock, 5))errorHandling("listen() error!");while(1){clientAddrSize = sizeof(clientAddr);clientSock = accept(servSock, (struct sockaddr*)&clientAddr, &clientAddrSize);if(-1 == clientSock)errorHandling("accept() error!");pthread_mutex_lock(&mutex);clientSocks[clientCount++] = clientSock;pthread_mutex_unlock(&mutex);pthread_create(&threadID, NULL, handleClient, (void*)&clientSock);pthread_detach(threadID); //线程结束后自动销毁内存printf("Connected client IP:%s\n", inet_ntoa(clientAddr.sin_addr));}close(servSock);return 0;
}void* handleClient(void *arg)
{int clientSock = *((int*)arg);int strLen = 0;int i;char msg[BUF_SIZE];while((strLen = read(clientSock, msg, sizeof(msg))) != 0)sendMsg(msg, strLen);pthread_mutex_lock(&mutex);for(i = 0; i < clientCount; i++){if(clientSock == clientSocks[i]){while(i++ < (clientCount - 1)) clientSocks[i] = clientSocks[i+1];//数组中删除客户端套接字break;}}clientCount--;pthread_mutex_unlock(&mutex);close(clientSock);return NULL;
}void sendMsg(char *msg, int len) //send to all
{int i;pthread_mutex_lock(&mutex);for(i = 0; i < clientCount; i++)write(clientSocks[i], msg, len);pthread_mutex_unlock(&mutex);
}void errorHandling(const char *msg)
{fputs(msg, stderr);fputc('\n', stderr);exit(1);
}
相关文章:
linux线程的基本知识
这里用的是Linux的pthread线程库,需要加pthread线程库。 线程的创建 第一个参数是线程id的地址。第二个参数是线程属性,一般为NULL。第三个是要执行的函数。第四个是函数的参数,一般也为NULL 线程的等待,第一个参数是线程的id,第…...
docker swarm 集群服务编排部署指南(docker stack)
Docker Swarm 集群管理 概述 Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机,使得容器可以组成跨主机的子网网络。Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用…...
ESP开发环境搭建
一、windows中搭建 esp-idf tool(可选),下载连接如下:https://dl.espressif.com/dl/esp-idf/?idf4.4 下载安装tools后进入vscode进行插件安装(未离线下载idf工具也可以通过第二步通过插件下载安装) 1. vscode安装编译环境 ESP-IDF 需要安装一些必备工…...
内网安全——ssH协议WindowsLinux密码获取hashcat
目录 (一)横向移动-Linux把场-ssH协议&RSA密匙凭证 (二)Windows-密码获取-在线离线读取&密文破解&a...
【编程入门】应用市场(安卓版)
背景 前面已输出多个系列: 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 《N种编程语言做个记事本》 目标 为编程初学者打造入门学习项目,使…...
【图像分类】卷积神经网络之LeNet5网络模型结构详解
写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 1. 前言 LeNet5算法是LeCun在1998年提出的卷积神经网络模型。大约90年代,由于支持向量机等算法的发现,深度学习…...
2023-JavaWeb最新整理面试题-TCP、Tomcat、Servlet、JSP等
Java基础面试题 一、JavaWeb专题 1.HTTP响应码有哪些 1、1xx(临时响应) 2、2xx(成功) 3、3xx(重定向):表示要完成请求需要进一步操作 4、4xx(错误):表示请…...
【云原生kubernetes】k8s Ingress使用详解
一、什么是Ingress 在上一篇关于k8s之service的使用一篇中提到,Service对集群之外暴露服务的主要方式有两种,NotePort和LoadBalancer,但这两种方式,都有一定的缺点,具体来说: NodePort 会占用很多集群机器…...
[数据结构]:顺序表(C语言实现)
目录 前言 顺序表实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-SeqListCommon.cpp 04-SeqListPositionOperation.cpp 05-SeqListValueOperation.cpp 结语 前言 此专栏包含408考研数据结构全部内容,除其中使用到C引用外,全为…...
【大厂高频必刷真题100题】《有序矩阵中第 K 小的元素》 真题练习第27题 持续更新~
有序矩阵中第 K 小的元素 给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。 请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n^2) 的解决方案。 示例 1: 输入:matrix = [[1,5,9…...
两年外包生涯做完,感觉自己废了一半....
先说一下自己的情况。大专生,17年通过校招进入湖南某软件公司,干了接近2年的点点点,今年年上旬,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了五年的功能测试…...
02- OpenCV绘制图形及图像算术变换 (OpenCV基础) (机器视觉)
知识重点 OpenCV用的最多的色彩空间是HSV. 方便OpenCV做图像处理img2 img.view() # 浅拷贝img3 img.copy() # 深拷贝split(mat) 分割图像的通道: b, g, r cv2.split(img) # b, g, r 都是数组merge((ch1, ch2, ch3)) 融合多个通道cvtColor(img, colorspace): 颜…...
猜数字大小 II
力扣链接 力扣 题目描述: 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字。你来猜我选了哪个数字。如果你猜到正确的数字,就会 赢得游戏 。如果你猜错了,那么我会告诉你,我选的数…...
CCNP350-401学习笔记(251-300题)
251、 Which IPv6 OSPF network type is applied to interface Fa0/0 of R2 by default? A. multipointB. broadcast C. Ethernet D. point-to-point 252、Which EIGRP feature allows the use of leak maps? A. neighborB. Stub C. offset-list D. address-family 253、W…...
掌握MySQL分库分表(二)Mysql数据库垂直分库分表、水平分库分表
文章目录垂直分表拆分方法举例垂直分库水平分表水平分库小结垂直角度(表结构不一样)水平角度(表结构一样)垂直分表 需求:商品表字段太多,每个字段访问频次不⼀样,浪费了IO资源,需要…...
算法训练营 day50 动态规划 单词拆分 多重背包理论基础
算法训练营 day50 动态规划 单词拆分 多重背包理论基础 单词拆分 139. 单词拆分 - 力扣(LeetCode) 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词…...
一文3000字用Postman从0到1实现UI自动化测试
“阅读本文大概需要4分钟。Postman不是做接口测试的吗?为什么还能做UI自动化测试呢? 其实,只要你了解Selenium的运行原理,就可以理解为什么Postman也能实现UI自动化测试了。 Selenium底层原理 运行代码,启动浏览器后…...
2023年美国大学生数学建模C题:预测Wordle结果建模详解+模型代码(一)
目录 前言 一、题目理解 背景 解析 字段含义: 建模要求 二、建模思路...
spring-boot 整合 前端框架 React 增删改查(附源码)
看了很多 关于 SpringBoot 增删改查 的文章 ,但是 React 前端框架这块似乎没什么人玩,一般都是Vue进行整合 ,所以想写一篇关于 React 整合 SpringBoot 增删改查的项目 React 学习区域 React中文教程: https://www.php.cn/doc/react/tutorial/…...
未来的城市:智慧城市定义、特征、应用、场景
智慧城市是通过连接一个地区的物理、经济和社会基础设施,以创新、有效和高效的方式应用和实施技术来发展城市的概念,以改善服务并实现更好的生活质量。智慧城市是一个将信息和通信技术融入日常治理的城市区域,旨在实现效率、改善公共服务、增…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
