linux线程的基本知识

news2024/11/14 14:06:36

这里用的是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   256
 
void* 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.coloradmin.cn/o/359743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VBA提高篇_27 OptionBOX_CheckBox_Frame_Image_VBA附加控件

文章目录1.单选按钮OptionBOX:2.复选框CheckBox:3.框架Frame:4.图像Image: (loadPictrue)5. VBA附加控件:6. 适用于很多控件的重要属性:1.单选按钮OptionBOX: 默认时,同一窗体的所有单选按钮均属于同一组,只能选中一个 可通过Frame控件进行分组解决. 2.复选框CheckBox: 一次可以…

备考软考系统分析师-1

系统分析师教程网盘资源&#xff1a;链接: https://pan.baidu.com/s/1ekHuCJJ3o5RrW1xeMkxhdA 提取码: 6666 信息系统战略规划 信息系统开发方法&#xff1a; 结构化法 瀑布模型 原型法 自顶向下 用于需求阶段较多 面向对象 自底向上 面向服务的方法 系统建模 政府信息…

在Excel接入 chatgtp (图文教学)

效果图 话不多说&#xff0c;开始教学 首先点击插入&#xff0c;然后点击获取加载项 office Excel 加载加载项时出错 解决办法_long_songs的博客-CSDN博客今天在添加维基百科的时候&#xff0c;怎么都添加不了&#xff0c;网上的办法都是关闭&#xff0c;重启&#xff0c;或者…

[架构之路-114]-《软考-系统架构设计师》-软件架构设计-7-软件架构评估

前言第7节 软件架构评估7.1 什么是架构评估/为什么要软件架构评估在软硬件系统总体架构设计完成之后&#xff0c;为保证架构设计的合理性、完整性和针对性&#xff0c;从根本上保证系统质量&#xff0c;降低成本及投资风险&#xff0c;需要对总体架构进行评估。7.2 软件架构评估…

word高效技巧:几个快速填充表格的操作方法

我们办公人员在面对大量表格数据的时候&#xff0c;都希望以最简便、快捷的方式完成对数据的填充、美化等整理工作。比如&#xff0c;日常工作中几种常用的Word表格填充类型&#xff1a;1. 填充序号&#xff1b;2. 填充文本&#xff1b;3. 填充颜色。因此&#xff0c;接下来给大…

你了解互联网APP推荐的背后逻辑么(下)?

上篇重点介绍了互联网APP在搜索交互场景下的通用逻辑&#xff0c;让大众对每天离不开的搜索进行了一个普遍介绍。这一篇&#xff0c;我们来聊聊抖音、头条等APP划一划这个动作背后&#xff0c;是怎么做推荐的。推荐的背后&#xff0c;离不开每个用户的数据&#xff0c;而且这个…

谈谈Linux内核的噪声

Linux内核是广被使用的操作系统&#xff0c;从嵌入式家用设备&#xff0c;航空航天设备到超级计算机&#xff0c;到处都有Linux内核的身影&#xff0c;这归功于Linux内核丰富的配置带来的巨大灵活性。 网络虚拟化和软件定义网络的发展&#xff0c;也从另外一个方面证实了在网络…

Java线程的6中状态

Java 线程的状态 Java线程有六种状态&#xff1a; 初始&#xff08;NEW&#xff09;、运行&#xff08;RUNNABLE&#xff09;、阻塞&#xff08;BLOCKED&#xff09;、 等待&#xff08;WAITING&#xff09;、超时等待&#xff08;TIMED_WAITING&#xff09;、终止&#xff08…

layui框架学习(8:动态操作选项卡)

Layui官网示例&#xff08;参考文献3&#xff09;中的选项卡部分除了介绍选项卡的样式外&#xff0c;还介绍了新增选项卡、删除选项卡、切换选项卡等动态操作选项卡方式&#xff0c;主要调用element模块中与选项卡相关的函数实现&#xff0c;除此之外&#xff0c;element模块还…

树莓派下安装OpenEuler

openEuler作为华为开源的应用于嵌入式设备的操作系统&#xff0c;正在受到越来越多的关注。树莓派是一个很好的应用场景&#xff0c;这篇文章就介绍下如何在树莓派上安装openEuler。   ps&#xff1a;openEuler要求树莓派的版本是4B 1.下载openEuler镜像 镜像网址&#xff1…

【K哥爬虫普法】百度、360八年乱战,robots 协议之战终落幕

我国目前并未出台专门针对网络爬虫技术的法律规范&#xff0c;但在司法实践中&#xff0c;相关判决已屡见不鲜&#xff0c;K哥特设了“K哥爬虫普法”专栏&#xff0c;本栏目通过对真实案例的分析&#xff0c;旨在提高广大爬虫工程师的法律意识&#xff0c;知晓如何合法合规利用…

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——MapReduce工作流程

1、流程示意图 MapReduce详细工作流程&#xff08;一&#xff09; MapReduce详细工作流程&#xff08;二&#xff09; 2、流程详解 上面的流程是整个MapReduce最全工作流程&#xff0c;但是Shuffle过程只是从第7步开始到第16步结束&#xff0c;具体Shuffle过程详解&#xff0…

作为Linux C/C++程序员必备的工具

Linux系统 可以选择centOS或者ubautu server(不建议选择桌面版本的)。不建议裸机安装&#xff0c;玩坏了就特别麻烦。不建议使用有桌面版本的ubautu&#xff0c;在一定程度有桌面的版本的会消耗性能。 如果经济实力允许&#xff0c;可以购买云服务器。 参考文章: Ubuntu server…

一款基于各大企业信息API渗透工具

功能 剑指HW/SRC&#xff0c;解决在HW/SRC场景下遇到的各种针对国内企业信息收集难题 使用支持以下API&#xff0c;并支持合并数据导出 爱企查 (未登陆信息带*) 企查查&#xff08;签名失效&#xff09; 天眼查 阿拉丁 酷安市场 七麦数据 站长之家 veryvp 查询信息 IC…

15-基础加强3-单元测试日志

文章目录1.单元测试1.1概述【理解】1.2特点【理解】1.3使用步骤【应用】1.4相关注解【应用】2.日志2.1概述【理解】2.2日志体系结构和Log4J【理解】2.3入门案例【应用】1.单元测试 1.1概述【理解】 JUnit是一个 Java 编程语言的单元测试工具。JUnit 是一个非常重要的测试工具…

荧光标记ATTO647N NHS,ATTO 647N SE,ATTO 647N-琥珀酰亚胺酯用于单分子检测

【中文名称】 ATTO 647N-琥珀酰亚胺酯&#xff0c;ATTO 647N-活性酯【英文名称】 ATTO 647N-NHS&#xff0c;ATTO 647N NHS&#xff0c;ATTO 647N SE&#xff0c;ATTO 647N-NHS ester【光谱图】【CAS号】N/A【分子式】C46H55ClN4O5【分子量】779.41【基团部分】 ATTO【纯度标准…

5.6配置BGP联邦和团体属性

5.3.3配置BGP联邦和团体属性 1. 实验目的 熟悉BGP联邦和团体属性的应用场景掌握BGP联邦和团体属性的配置方法2. 实验拓扑 实验拓扑如图5-6所示: 图5-6:配置BGP联邦和团体属性 3. 实验步骤 (1)IP地址的配置 R1的配…

【Jmatpro 10.0】根据材料牌号输出应力-应变曲线

我的主页&#xff1a; 技术邻&#xff1a;小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩&#xff1a;小铭的ABAQUS学习的个人空间csdn&#xff1a;qgm1702 博客园文章链接&#xff1a; https://www.cnblogs.com/aksoam/p/17121006.html 1.前提条件 Jmatpro …

复盘会如何开出新花样?10种方式让你开出让人惊喜的复盘会【附复盘问题列表】

复盘是每个PMO和项目经理必备的技能之一&#xff0c;咱们分享过很多复盘的技巧和方法&#xff0c;如下&#xff1a;但是大家都会有个问题&#xff0c;那就是复盘形式单一&#xff0c;团队复盘几次就会失去兴趣&#xff1f;失去兴趣之后效果自然不会太好&#xff0c;如何把让大家…

C++设计模式(17)——备忘录模式

亦称&#xff1a; 快照、Snapshot、Memento 意图 备忘录模式是一种行为设计模式&#xff0c; 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 问题 假如你正在开发一款文字编辑器应用程序。 除了简单的文字编辑功能外&#xff0c; 编辑器中还要有设置文本格…