线程 在linux系统中

1.Linux线程实现

2.Linux线程的创建和终止

3.Linu线程的互斥和同步

Linux或unix系统多任务,线程处理大并发的客户端请求

进程是资源管理的最小单位,线程是程序执行的最小单位

针对在进程中的每一个操作,都是在后台去启动一个一个线程来执行处理,线程是负责进程中某个具体操作,根据需要,可以在进程中启动一个或多个线程。每个线程共享其附属进程的所以资源,包括打开的文件,内存页面,信号标识及动态分配的内存等。

因为线程比进程比起来很小,所以相对来说,线程花费更少的CPU资源

在操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持多处理器,并且减小进程上下文切换的开销

进程根据系统调度要互相切换,时间片给进程,

每个进程都有自己的数据段,代码段,堆栈段,线程通常叫做轻量级进程,

1.linux搭建的服务器,多个客户端需要访问服务器,需要发送请求,服务器响应完后,发回页面,服务器对客户端的请求采用线程处理大并发客户端请求

线程与进程关系:

线程是属于进程的,线程运行在进程空间内,同一进程所产生的进程共享同一用户内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除, 进程管理着资源(比如CPU,内存,文件等),而将线程分配到某个CPU上执行,如果没有可以去创建线程,一个进程只有一个主控线程,创建的线程称为子线程,线程的执行也要根据优先级进行任务调度

默认情况,一个进程启动只有一个线程(主线程)

通过主控线程可以创建很多线程,这些线程都共享进程所有的资源

现在的操作系统都是多任务,多用户,分时操作系统,可以创建多个进程,根据抢占式调度,根据优先级,轮流占据CPU,各个进程从就绪态切换为运行态,CPU会给这个进程分配一个时间片,进程必须在这个时间片中运行完毕,如果没有运行完毕,暂时退出,阻塞,CPU被其他进程占有,CPU再发分配时间片给其他进程,被阻塞的进程等待被CPU重新发分配时间片才会继续运行

如果只有一个进程

CPU分配给进程的时间片,在进程运行里面,只有一个线程在获取CPU,去执行,多个线程,也要根据优先级实现系统调度,

有多个线程,CPU给进程的时间片时间大于此进程里面任何单个线程被CPU分配的时间片。

线程分类

线程按照其调度可分为用户级线程内核级线程

用户级线程:主要解决的是上下文切换的问题

内核级线程:由内核调度机制实现

用户级线程需要绑定内核级线程,这样才能实现用户级线程的调度执行。

默认情况下,用户级线程和内核线程是一对一,也可以多对一,这样实时性就会比较差

用户级线程分配的时间片以内核级线程为准

Linux线程实现

在linux中,一般采用pthread线程库(继承于unix操作系统),实现线程的访问与控制,由POSIX

提出,具有良好的可移植性

Liunx线程程序编译需要在gcc上链接库pthread   gcc -lpthread  

进程标识是pid

线程标识

1.每个进程内部的不同线程都有自己唯一的标识(ID) 

2.线程标识只在它所述的进程环境中有效

3.线程标识是pthread_t数据类型,线程标识的类型

线程创建

在主控线程中调用系统调用

第一个是传递线程标识符,第二个是线程属性,不需要为NULL,

终止方式

gcc -p.c -lpthread  //加-lpthread链接pthread库


//龟兔赛跑线程
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <math.h>//定义线程运行函数,乌龟和兔子的线程轮流交替
void* th_fn(void *arg)
{int distance = (int)arg;  //强制类型转换int i;for(i = 1; i <= distance; i++){printf("%lx run %d\n", pthread_self(), i);//drand48()用于产生0~1之间的随机数int time = (int)(drand48() * 100000);usleep(time);  //微妙级别延时}return (void*)0;
}int main(void)
{int err;pthread_t  rabbit, turtle;  //兔子和乌龟的线程标识符   //创建rabbit线程,第一个是线程标识符,第二个是线程属性,//第三个是线程运行函数,第四个是传给线程函数的参数//创建成功返回0,错误返回错误编号if((err = pthread_create(&rabbit, NULL, th_fn, (void*)50)) != 0){perror("pthread_create error");}//创建turtle线程if((err = pthread_create(&turtle, NULL, th_fn, (void*)50)) != 0){perror("pthread_create error");}//先运行子线程//主控线程调用pthread_join(),自己会阻塞,//直到rabbit和turtle都结束方可运行//pthread_join()用于阻塞线程,谁调用,谁阻塞pthread_join(rabbit, NULL);pthread_join(turtle, NULL);//sleep(5);  //睡眠主控线程,阻塞主控子线程cleaprintf("control thread id:%lx\n", pthread_self());printf("finished\n");return 0;  //整个进程结束
}

线程创建第二个案例,传入线程函数里的是一个结构体

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>typedef struct{char name[20];int time;int start;int end;
}RaceArg;void* th_fn(void* arg)
{RaceArg *r = (RaceArg*)arg;int i = r->start;for(; i <= r->end; i++){printf("%s(%lx) running %d\n",r->name, pthread_self(), i);usleep(r->time);}return (void*)0;
}int main(void)
{int err;pthread_t rabbit, turtle;RaceArg r_a = {"rabbit", (int)(drand48()*10000000), 20, 50};RaceArg t_a = {"turtle", (int)(drand48()*10000000), 10, 60};if((err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a)) != 0){printf("Pthread_create error");}if((err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a)) != 0){printf("Pthread_create error");}pthread_join(rabbit, NULL);pthread_join(turtle, NULL);return 0;
}

进程和线程的内存信息

主控线程使用同一个线程调用函数被pthread_create()了两次创建了两个子线程,生成了两个子线程的栈空间,在各自的栈中存放了各自的线程调用函数所需的局部变量

然而定义的全局变量存放在数据段,进程中的各个线程对这个全局变量是共享的,可以对其进行修改,所有线程都能对其访问的资源叫做共享资源,引发线程不安全,要做到线程安全,互斥和同步来解决          多线程编程   尽量引用局部变量,这样线程就是安全的

线程终止

1.主动终止

线程主动终止pthread_exit();

exit();//进程主动终止

2.被动终止

pthread_cancel();//线程可以被同一进程的其他线程取消,tid为被终止的线程标识符

pthread_join();调用这个函数的线程会阻塞,直到等到等待的线程结束,会回收标识符ID线程的资源,类似进程里用的系统调用函数wait()

pthread_join(pthread_t th, (void**) thread_return)  //第二个参数接收th线程的返回值

下面的代码主要是注意指针的转换

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>typedef struct
{int d1;int d2;
}Arg;void*   th_fn(void *arg)
{Arg *r = (Arg*)arg;return (void*)(r->d1 + r->d2);
}int main(void)
{int err;pthread_t th;Arg r = {20, 50};if((err = pthread_create(&th, NULL, th_fn, (void*)&r)) != 0) //传r的地址{perror("pthread_create error");}/*  int *result;pthread_join(th, (void**)&result); //传result的地址printf("result is %d\n", (int)result);*/int result;pthread_join(th, (void*)&result); //获取线程函数的返回值printf("result is %d\n", result);return 0;
}

线程运行函数关键usleep();

这样可以让不同线程不至于让一个线程霸占完

//定义线程运行函数,乌龟和兔子的线程轮流交替
void* th_fn(void *arg)
{int distance = (int)arg;  //强制类型转换int i;for(i = 1; i <= distance; i++){printf("%lx run %d\n", pthread_self(), i);//drand48()用于产生0~1之间的随机数int time = (int)(drand48() * 100000);usleep(time);  //微妙级别延时,使多个线程交替执行}return (void*)distance;
}

线程清理和控制函数

线程清理函数

pthread_cleanup_push()

pthread_cleanup_pop()

excute == 1执行线程处理函数,excute==0不执行线程处理函数

#include <stdint.h>

intptr_t类型

intptr_t 是 C 语言中的一种整数类型,定义在 <stdint.h> 头文件中。intptr_t 是一个有符号整数类型,其大小足以容纳指针的值。它的主要用途是在需要将指针转换为整数或将整数转换为指针的情况下,确保这种转换是安全的和可移植的。

关键特性

  1. 大小

    • intptr_t 的大小与指针的大小相同,这意味着它可以无损地存储指针的值。
    • 在 32 位系统上,intptr_t 通常是 32 位整数。
    • 在 64 位系统上,intptr_t 通常是 64 位整数。
  2. 有符号性

    • intptr_t 是一个有符号整数类型,这意味着它可以表示负数。
  3. 用途

    • 将指针转换为整数,以便在需要整数的地方使用。
    • 将整数转换为指针,以便在需要指针的地方使用。

示例代码

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  //包含intptr_t类型//定义线程清理函数
void clean_fn(void* arg)
{char *s = (char*)arg;printf("clean_func: %s\n", s);
}//线程运行函数
//线程清理函数在线程结束之前调用
void*   th_fn(void *arg)
{intptr_t excute = (intptr_t)arg;//第二个参数传递给线程清理函数pthread_cleanup_push(clean_fn, "first clean func"); //线程处理函数压栈pthread_cleanup_push(clean_fn, "second clean func");printf("thread running %lx\n", pthread_self());//线程控制函数,excute为1执行pthread_cleanup_push(th_fn, arg);pthread_cleanup_pop(excute);  //控制是否执行线程处理函数,0不执行,1执行pthread_cleanup_pop(excute);return (void*)0;
}int main(void)
{int err;pthread_t th1, th2;//子线程1,传递if((err = pthread_create(&th1, NULL, th_fn, (void*)(intptr_t)1)) != 0){perror("pthread create error");}pthread_join(th1, NULL);printf("th1(%lx) finished\n", th1);//子线程2if((err = pthread_create(&th2, NULL, th_fn, (void*)1)) != 0){perror("pthread create error");}pthread_join(th2, NULL);printf("th2(%lx) finished\n", th2);return 0;
}

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

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

相关文章

ImageSharp报错

错误信息 System.MissingMethodException: Method not found: System.Span1<SixLabors.ImageSharp.PixelFormats.Rgba32> SixLabors.ImageSharp.Memory.Buffer2D1.GetRowSpan(Int32).需要升级项目 原来仅升级了SixLabors.ImageSharp没有升级drawing&#xff0c;都升级到…

网站保护神器,雷池社区版的隐藏文件

SafeLine&#xff0c;中文名 “雷池”&#xff0c;是一款简单好用, 效果突出的 Web 应用防火墙(WAF)&#xff0c;可以保护 Web 服务不受黑客攻击。 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、XSS、 代码注入、命…

线程的理解及基本操作

目录 一、线程的理解 &#xff08;1&#xff09;什么是线程呢&#xff1f; &#xff08;2&#xff09;线程的优缺点及异常 二、线程的基本操作 &#xff08;1&#xff09;创建一个新的进程 &#xff08;2&#xff09;获取线程id &#xff08;3&#xff09;线程终止 &…

常见网安面试题

《Java代码审计》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484219&idx1&sn73564e316a4c9794019f15dd6b3ba9f6&chksmc0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene21#wechat_redirect 《网安面试指南…

初探Servlet

文章目录 1. Servlet概述1.1 定义1.2 作用 2. 主要知识点2.1 生命周期2.2 请求处理2.3 Servlet配置 3. 案例演示3.1 创建Web应用项目3.2 修改项目工件名3.3 重新部署Web项目3.4 创建WelcomeServlet3.5 编写doGet方法代码3.6 编写doPost方法代码3.7 访问WelcomeServlet 4. 小结 …

【modbus协议】Modbus-TCP消息帧格式

文章目录 协议描述Modbus Application Header 结构示例与其他部分的关系作用总结 协议描述 在ModbusTCP/IP协议中,串行链路中的主/从设备分别演变为客户端/服务器端设备。即客户端相当于主站设备,服务器端相当于从站设备。基于TCP/IP网络的传输特性。Modbus协议在TCP/IP上的实…

VsCode | 修改内置字体为JetBrains Mono NL

文章目录 一、下载JetBrains Mono NL字体二、VsCode进行字体的设置 一、下载JetBrains Mono NL字体 字体下载 下载完成以后解压找到JetBrainsMono-2.304\fonts\ttf文件夹下&#xff0c;全选鼠标右键点安装即可。 注意&#xff1a;一定要全部安装&#xff0c;否则字体样式可…

QT仿QQ聊天项目,第二节,美化登录界面

一&#xff0c;控件起名和设置整体样式 目录 一&#xff0c;控件起名和设置整体样式 二&#xff0c;设置局部控件样式 三&#xff0c;设置gif动态背景 四&#xff0c;设置账号密码框样式 五&#xff0c;头像图片设置 给控件起的名字&#xff1a; 关闭按钮: btn_close 缩小…

轻松部署自己的AI聊天助手LocalGPT并实现无公网IP远程交互

文章目录 前言环境准备1. localGPT部署2. 启动和使用3. 安装cpolar 内网穿透4. 创建公网地址5. 公网地址访问6. 固定公网地址 前言 本文主要介绍如何本地部署LocalGPT并实现远程访问&#xff0c;由于localGPT只能通过本地局域网IP地址端口号的形式访问&#xff0c;实现远程访问…

N-154基于springboot酒店预订管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;AdminLTEBootstrapLayUIHTMLjQuery 服务端技术&#xff1a;springbootmybatis-plusthymeleaf 本项目分前台和后台…

Banana Pi BPI-R3路由器开发板运行 OrayOS物联网系统

近日&#xff0c;Banana PI开发板宣布与贝锐达成战略合作&#xff0c;贝锐OrayOS现已成功适配Banana PI的BPI-R3型号&#xff0c;并计划进一步扩展硬件支持&#xff0c;包括目前Banana PI热销的BPI-R4、BPI-R3 Mini等更多型号。这一合作为用户提供了更广泛的开发板选择&#xf…

范式转移:从协程、回调到异步

本文使用 CC BY-NC-ND 4.0 许可。 原文&#xff1a;英文版 | 中文版 协程、回调和异步每一个单独拎出来讲都不难&#xff0c;但它们之间的关系却非常烧脑&#xff0c;迄今为止我还没见过哪篇文章能讲清楚的&#xff0c;所以在这里我尝试用最简单的思路讲解清楚&#xff1a;如…

Pytorch学习--神经网络--非线性激活

一、用法 torch.nn.ReLU 图像处理中的应用&#xff1a;在图像处理任务中&#xff0c;ReLU 激活函数能够增强特征提取的能力&#xff0c;使网络更好地捕捉图像的细节和边缘。这是因为 ReLU 对大部分负数响应为零&#xff0c;能在一定程度上减少网络计算量&#xff0c;并对特征…

Objective-C 音频爬虫:实时接收数据的 didReceiveData_ 方法

在互联网技术领域&#xff0c;数据的获取和处理是至关重要的。尤其是对于音频内容的获取&#xff0c;实时性和效率是衡量一个爬虫性能的重要指标。本文将深入探讨在Objective-C中实现音频爬虫时&#xff0c;如何高效地使用didReceiveData:方法来实时接收数据&#xff0c;并通过…

企业自建邮件系统选U-Mail ,功能强大、安全稳定

在现代企业运营中&#xff0c;电子邮件扮演着至关重要的角色&#xff0c;随着企业规模的增长和业务的多样化&#xff0c;传统的租用第三方企业邮箱服务逐渐显现出其局限性。例如&#xff0c;存储空间受限、数据安全风险、缺乏灵活的管理和备份功能&#xff0c;以及无法与其他企…

C++在实际项目中的应用第二节:C++与区块链

第五章&#xff1a;C在实际项目中的应用 第二课&#xff1a;C与区块链 区块链技术因其去中心化、不可篡改和透明性而受到广泛关注。在这门课程中&#xff0c;我们将深入探讨区块链的基本原理、智能合约的开发以及实际应用的案例分析&#xff0c;重点使用 C 作为实现语言&…

雷池社区版中升级雷池遇到问题

关于升级后兼容问题 版本差距过大会可能会发生升级后数据不兼容导致服务器无法起来 跨多个版本&#xff08;超过1个大版本号&#xff09;升级做好数据备份&#xff0c;遇到升级失败可尝试重新安装解决 升级提示目录不对 在错误的目录下执行&#xff08;比如 safeline 的子目…

TCP/IP Attack Lab

网络拓扑&#xff1a; Task 1: SYN Flooding Attack 收到攻击之前&#xff0c;在Victim主机查看网络连接的状态: 在攻击之前使用User1主机(10.9.0.6)访问Victim(10.9.0.5)主机的 Telnet服务: Task 1.1: Launching the Attack Using Python 在Atacker上建立文件attack-1.py…

Jvm中的堆和栈

JVM中的堆和栈分别存放不同的数据类型和内容。 ‌栈&#xff08;Stack&#xff09;‌&#xff1a; 存储基本数据类型&#xff08;如int, char, boolean等&#xff09;和对象的引用。存储局部变量、方法调用、程序运行状态、方法返回值等。每个线程都有一个独立的线程栈&#…

我为什么投身于青少年AI编程?——打造生态圈(三)

第五部分 青少年AI编程生态圈 一、生态圈 主要涵盖家庭、社区/中小学、高校高职、主管部门。 1、家庭 我们与社区/中小学一道打造让家长满意的模式。 教得好&#xff1a; 费用少&#xff1a; 家门口&#xff1a; 2、社区/中小学 社区党群服务中心和中小学都有大面积科普…