linux线程的基本知识

news/2024/3/29 4:56:55/文章来源:https://blog.csdn.net/weixin_53344209/article/details/129093558

这里用的是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);
}

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

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

相关文章

SpringBoot之DEBUG远程调试黑科技?

所谓的远程调试就是服务端程序运行在一台远程服务器上&#xff0c;我们可以在本地服务端的代码&#xff08;前提是本地 的代码必须和远程服务器运行的代码一致&#xff09;中设置断点&#xff0c;每当有请求到远程服务器时时能够在本地知道 远程服务端的此时的内部状态。 简单的…

10.现代循环神经网络

10.现代循环神经网络 目录 门控循环单元&#xff08;GRU&#xff09;门控隐状态 重置门和更新门候选隐状态 隐状态从零开始实现 初始化模型参数定义模型训练与预测 简洁实现总结 长短期记忆网络&#xff08;LSTM&#xff09; 门控记忆元 输入门、忘记门和输出门候选记忆元记忆…

论文复现:模拟风电不确定性——拉丁超立方抽样生成及缩减场景(Matlab)

风电出力的不确定性主要源于预测误差&#xff0c;而研究表明预测误差&#xff08;e&#xff09;服从正态分布且大概为预测出力的10%。本代码采用拉丁超立方抽样实现场景生成[1,2]、基于概率距离的快速前代消除法实现场景缩减[3]&#xff0c;以此模拟了风电出力的不确定性。 1 …

蓝桥杯刷题025——推导部分和(加权并查集)

2022省赛 问题描述 对于一个长度为 N 的整数数列 ​, 小蓝想知道下标 l 到 r 的部 分和是多少? 然而, 小蓝并不知道数列中每个数的值是多少, 他只知道它的 M 个部分和 的值。其中第 i 个部分和是下标 ​ 到 的部分和 , 值是 。 输入格式 第一行包含 3 个整数 N、M 和 Q 。分…

基于DSP+FPGA的机载雷达伺服控制系统的硬件设计与开发

机载雷达是以飞机为载体的各种雷达天线的总称&#xff0c;主要用于空中侦察、警戒、保 证航行准确与安全[1]。随着航空航天技术的飞速发展&#xff0c;以及微电子、计算机和高速集 成电路等新型技术在军事领域的广泛应用[2]&#xff0c;各国都研制出了许多新型战机和导弹,机 载…

企业微信的聊天机器人来了,免费下载(Python版)

大家好&#xff0c;这里是程序员晚枫&#xff0c;个人网址&#xff1a;python-office.com 上次分享了微信机器人的视频以后&#xff0c;视频下面有一个热门评论&#xff1a; 什么时候开发企业版微信机器人&#xff1f;自动回复、自动群发等等~ 在经历了一段时间的查找和开发以…

【基础算法】之 冒泡排序优化

冒泡排序思想基本思想: 冒泡排序&#xff0c;类似于水中冒泡&#xff0c;较大的数沉下去&#xff0c;较小的数慢慢冒起来&#xff08;假设从小到大&#xff09;&#xff0c;即为较大的数慢慢往后排&#xff0c;较小的数慢慢往前排。直观表达&#xff0c;每一趟遍历&#xff0c;…

Docker----------day3

常规安装大体步骤 1.安装tomcat 1.查找tomcat docker search tomcat2.拉取tomcat docker pull tomcat3.docker images查看是否有拉取到的tomcat 4.使用tomcat镜像创建容器实例(也叫运行镜像) docker run -it -p 8080:8080 tomcat5.新版tomcat把webapps.dist目录换成webapp…

【大数据离线开发】7.4 HBase数据保存和过滤器

7.4 数据保存的过程 注意&#xff1a;数据的存储&#xff0c;都需要注意Region的分裂 HDFS&#xff1a;数据的平衡 ——> 数据的移动&#xff08;拷贝&#xff09;HBase&#xff1a;数据越来越多 ——> Region的分裂 ——> 数据的移动&#xff08;拷贝&#xff09; …

清理bib文件(删除重复项,仅保留tex中引用的条目)

在写latex文件的过程中&#xff0c;经常会遇到添加了一堆文献的bibtex到bib文件中&#xff0c;有时候文章一长同一篇文献用不同的cite-key引用了多次&#xff0c;同时也会有一些文献最后并没被正文引用&#xff0c;这就需要对bib文件进行清理。 删除重复项 可以用JabRef 在J…

经理与员工工资关系-课后程序(JAVA基础案例教程-黑马程序员编著-第四章-课后作业)

【案例4-6】经理与员工工资案例&#xff08;利用多态实现&#xff09; 欢迎点赞关注收藏 【案例介绍】 案例描述 某公司的人员分为员工和经理两种&#xff0c;但经理也属于员工中的一种&#xff0c;公司的人员都有自己的姓名和地址&#xff0c;员工和经理都有自己的工号、工…

不同投票需要的不同上传方式outlook 投票功能怎么设置投票 html5

“艺空间手造坊”网络评选投_投票方式的选择_免费图文教学投票教学关于微信投票&#xff0c;我们现在用的最多的就是小程序投票&#xff0c;今天的网络投票&#xff0c;在这里会教大家如何用“活动星投票”小程序来进行投票。我们现在要以“艺空间手造坊”为主题进行一次投票活…

AcWing1015.摘花生

AcWing 1015. 摘花生Hello Kitty想摘点花生送给她喜欢的米老鼠。她来到一片有网格状道路的矩形花生地(如下图)&#xff0c;从西北角进去&#xff0c;东南角出来。地里每个道路的交叉点上都有种着一株花生苗&#xff0c;上面有若干颗花生&#xff0c;经过一株花生苗就能摘走该它…

Java并发知识点

文章目录1. start()和run()方法的区别&#xff1f;2. volatile关键字的作用&#xff1f;使用volatile能够保证&#xff1a;防止指令重排3. sleep方法和wait方法有什么区别&#xff1f;sleep()方法4. 如何停止一个正在运行的线程&#xff1f;方法一&#xff1a;方法二&#xff1…

多重继承的虚函数表

同一个类,不同对象使用同一张虚函数表 不同类使用不同的虚函数表 子类自己添加的虚函数(非重写),在VS中是将此放在第一个继承类的虚函数表里. #include <iostream> using namespace std;class Father { public:virtual void func1() { cout << "Father::f…

<Linux>vscode搭建Linux远程开发工具

一、下载vscode&#x1f603;可以去vscode的官网下载&#xff0c;不过是外网下载速度较慢提速可以参考&#xff1a;(81条消息) 解决VsCode下载慢问题_vscode下载太慢_wang13679201813的博客-CSDN博客官网&#xff1a;Visual Studio Code - Code Editing. Redefined这里推荐的是…

【数据结构】二叉树的四种遍历

写在前面首先二叉树是一个大家族&#xff0c;这篇文章就讲一讲二叉树的遍历&#xff1a;递归遍历迭代遍历先识概念二叉树的存储结构&#xff0c;可以为顺序存储&#xff0c;即使用数组&#xff1b;也可以为链式存储&#xff0c;即使用链表。我们使用较多的就是链式存储结构&…

Ceres的自动求导实现原理剖析

目录数学原理实现原理总结首先注意数值求导和自动求导在使用的时候的不同之处。 实际上&#xff0c;正是自动求导这个地方使用了类模板&#xff0c;导致它不仅可以传入参数&#xff0c;还可以传入Jet类型的数据&#xff0c;从而实现了参数的雅可比矩阵的计算&#xff0c;完成自…

TPM密钥管理、使用

前面讲过证书相关内容&#xff0c;除了在软件方面有所应用外&#xff0c;在硬件方面也有很多应用。本次讲一下TPM相关的内容。 一、TPM介绍 1.1背景 TCG基于硬件安全的架构是为应对1990s后期日益增多的复杂恶意软件攻击应用而生的。当时以及现在&#xff0c;抵御PC客户端网络…

树状数组(高级数据结构)-蓝桥杯

一、简介树状数组 (Binary Indexed Tree,BIT)&#xff0c;利用数的二进制特征进行检索的一种树状结构。一种真正的高级数据结构&#xff1a; 二分思想、二叉树、位运算、前缀和。高效!代码极其简洁!二、基本应用数列a1,a2,....,an&#xff0c;操作&#xff1a;单点修改&#xf…