Linux系统编程之--多线程

一.线程概述

线程是允许应用程序并法执行多个任务的一种机制,提高操作系统的运行效率.

线程是轻量级的进程(LWP),在Linux环境下线程的本质仍是进程

查看指定进程的LWP号:ps -LF pid

二.进程与线程的区别(重点)

一个进程可以包含多个线程,同一个程序中的所有线程均会独立执行相同的程序,且共同享用统一份全局内存区域(初始化数据段,未初始化数据段..)

 进程是cpu分配资源的最小单位,线程是操作系统调度执行的最小单位

     进程间的信息难以共享。由于除去只读代码段外,父子进程并未共享内存,
    因此必须采用一些进程间通信方式,在进程间进行信息交换。

     调用 fork()来创建进程的代价相对较高,即便利用写时复制技术, 仍热需要复制诸如内存页表和文件描述符表之类的多种进程属性,这意味着fork()调用在时间上的开销依然不菲。

 线程之间能够方便、快速地共享信息。只需将数据复制到共享(全局或堆)变量中即可

创建线程比创建进程通常要快10倍甚至更多。线程间是共享虚拟地址空间的,无需采用写时复制来复制内存,也无需复制页表

 三.线程的共享资源与非共享资源

共享资源


    进程 ID 和父进程 ID
    进程组 D 和会话 ID
    用户 ID和用户组 ID
    文件描述符表
    信号处置
    文件系统的相关信息:文件权限掩码(umask),当前工作目录
    虚拟地址空间(除栈、代码段)

非共享资源


    线程 ID
    信号掩码
    线程特有数据
    error
    实时调度策略和优先级
    栈,本地变量和函数的调用链接信息

四.线程的常用系统调用和实例

1.pthread_create

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
/*
一般情况下main函数所在线程叫做主线程,其余创建的称之为子线程程序中默认只有一个进程,fork()调用后,会有两个进程
程序中默认只有一个线程,pthread_create()调用后,会有两个线程int pthread_create(pthread_t *thread, const pthread_attr t *attr,void *(*start_routine)(void *),void *arg);-功能: 创建一个线程-参数:-thread :传出参数,线程创建成功后,子线程的线程id被写入到这个变量中-attr: 设置线程的属性,一般使用默认值, NULL-start_routine : 函数指针,这个函数是子线程需要处理的逻辑代码-arg : 给第三个参数使用,主要是传参-返回值-成功:返回0-失败:返回一个错误号,这个错误号和之前的errno不一样,不能通过perror()输出获取错误号信息: char * strerror(int errnum)
*/
void *pthread_callback(void *arg)
{printf("child1 thread...,获取到的num=%d\n",*(int *)arg);return NULL;
}
int main()
{//我需要创建一个子线程pthread_t tid;int num = 10;int ret = pthread_create(&tid,NULL,pthread_callback,(void *)&num);if(ret != 0){char *error_set = strerror(ret);printf("error : %s\n",error_set);}for(int i = 0; i < 5; i++){printf("%d\n",i);}sleep(1);return 0; //exit(0);
}

2.pthread_exit

/*
void pthread_exit(void *retval);-功能:  终止一个线程,在哪个线程中调用就说明终止哪个线程参数:retval:需要传递一个指针,作为一个返回值,可以在pthread_join()中获取到pthread_t pthread_self(void);-功能 : 获取当前线程的id
int pthread_equal(pthreadt tl,pthread t t2);-功能:比较两个线程id是否相等不同的操作系统:pthread_t 类型的实现不一样,有的是无符号长整型有的是使用结构体去实现
*/#include <stdio.h>
#include <pthread.h>
#include <string.h>void * thread_callback(void *arg)
{printf("子线程id=%ld; 收到数据:%s\n",pthread_self(),(char *)arg);return NULL; //pthread_exit(NULL);
}
int main()
{pthread_t tid;char * s = "我叫hello world";int ret = pthread_create(&tid,NULL,thread_callback,(void *)s);if(ret != 0){printf("pthread_create error:%s\n",strerror(ret));}for(int i = 0; i < 5; i++){printf("%d\n",i);}printf("子线程id:%ld;   主线程的id:%ld\n",tid,pthread_self());//让主线程退出,当主线程退出时不会影响其他运行中的线程pthread_exit(NULL);return 0;
}

3.pthread_join

/*
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);-功能:和一个已经终止的线程进行连接(一般是主线程回收其他线程数据)回收子线程的资源这个函数是阻塞函数,若是没有子线程去回收,那么会一直阻塞在这里一般在主线程中使用-参数:thread:需要回收的子线程的idretval:二级指针,接受子线程退出时的返回值-成功:返回0-错误:返回错误号
*/#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
int value = 10;
void *pthread_callback(void *arg)
{printf("子线程:%ld,收到数据:%s\n",pthread_self(),(char *)arg);sleep(3);pthread_exit((void *)&value); //return (void *)&value
}
int main()
{pthread_t tid;char *s = "hello world";int ret = pthread_create(&tid,NULL,pthread_callback,s);if(ret != 0){strerror(ret);return -1;}printf("子线程:%ld,主线程:%ld\n",tid,pthread_self());//主线程调用pthread_join回收子线程的资源int * pthread_retval;ret = pthread_join(tid,(void **)&pthread_retval); //不需要获取子线程退出的返回值,需要阻塞等待子线程结束if(ret != 0){strerror(ret);return -1;}printf("exit data : %d\n",*pthread_retval);printf("回收子线程资源成功\n");pthread_exit(NULL);return 0;
}

4.pthread_detach

/*
#include <pthread.h>int pthread_detach(pthread_t thread);-功能:分离一个线程,被分离的线程在终止的时候,会自动释放资源返回给系统1.不能多次分离,会产生不可预料的行为2.不能去连接一个已经分离的线程,会报错-参数:需要分离的线程的id-返回值:成功:0失败:返回错误号
*/#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>void *thread_cal(void *arg)
{printf("子线程id=%ld.收到数据%s:\n",pthread_self(),(char *)arg);return NULL;
}
int main()
{pthread_t tid;int ret = pthread_create(&tid,NULL,thread_cal,NULL);if(ret  != 0){char *error_s = strerror(ret);printf("pthread_create error:%s\n",error_s);}printf("主线程id:%ld,子线程id:%ld\n",pthread_self(), tid);//设置子线程分离pthread_detach(tid); //对子线程进行分离,现在子线程分离后,其结束时资源不需要主线程释放//对分离后的子线程进行连接会报错ret = pthread_join(tid,NULL);if(ret  != 0){char *error_s = strerror(ret);printf("pthread_create error:%s\n",error_s);}pthread_exit(NULL);//主线程退出return 0;
}

5.pthread_cancel

/*
#include <pthread.h>int pthread_cancel(pthread_t thread);-功能:发送一个取消的请求给我们的线程,让线程终止,并不是说调用这个函数后,线程会立刻终止取消某个线程,终止某个线程的运行,但不是立马终止而是当子线程执行到一个取消点,线程才会终止取消点:系统规定的一些系统调用,我们可以粗略的理解为从用户区到内核这个位置称之为取消点
*/#include <pthread.h>
#include <stdio.h>
#include <string.h>void *tid_callback(void *arg)
{printf("子线程启动成功,子线程tid:%ld\n",pthread_self());for(int i = 0; i < 100; i++){printf("child %d\n",i);}return NULL;
}int main()
{pthread_t tid;int ret = pthread_create(&tid,NULL,tid_callback,NULL);if(ret != 0){char *errormessage = strerror(ret);printf("pthread_create error: %s\n",errormessage);}//取消线程ret = pthread_cancel(tid);if(ret != 0){char *errormessage = strerror(ret);printf("pthread_cancel error: %s\n",errormessage);}for(int i = 0; i < 5; i++){printf("%d\n",i);}printf("主线程tid:%ld, 子线程tid:%ld\n",pthread_self(),tid);pthread_exit(NULL);return 0;
}

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

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

相关文章

技术总结(二十四)

一、Redis 分布式锁的常见使用场景有哪些&#xff1f; 资源竞争控制 数据库事务控制&#xff1a;在分布式系统中&#xff0c;多个服务可能会同时对数据库中的同一行数据进行操作。例如&#xff0c;在一个电商系统里&#xff0c;多个订单处理服务可能会同时尝试更新同一个订单的…

webWorker基本用法

我们都知道js是一个单线程的语言&#xff0c;当线程堵塞时&#xff0c;可能会导致页面无法正常交互&#xff0c;如一些复杂的可视化处理。即使是异步处理&#xff0c;也只是将其暂存到任务队列中去&#xff0c;等主线程执行完后依然会从任务队列中取过去。 为此&#xff0c;js提…

【1】虚拟机安装

1.安装VMware WorkStation Pro VMware下载地址&#xff1a; 2.新建虚拟机 centos7下载地址&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云

2-149 基于matlab的LDPC译码性能分析

基于matlab的LDPC译码性能分析&#xff0c;LDPC&#xff08;Low-Density Parity-Check&#xff09;码作为编码技术&#xff0c;具有优秀的纠错性能和较低的编解码复杂度。为保证可靠的数据传输&#xff0c;对传输过程中可能出现的信道噪声、干扰等进行模拟和分析。分析对比了误…

游戏开发--C#面试题

游戏开发--C#面试题 C#1. 值类型和引用类型的区别2. 重载和重写的区别3. ArrayList和List的区别4. List底层是什么实现的&#xff1f;5. 抽象类和接口的区别6. 静态成员和⾮静态成员的区别7. 装箱和拆箱是指什么&#xff1f;8. 值和引用类型在变量赋值时的区别是什么&#xff1…

Systemd:tmpfiles

Systemd提供了一个结构化的可配置方法来管理临时文件和目录,即systemd-tmpfiles,可以创建、删除和管理临时文件的服务。 $ systemctl list-units --all | grep systemd-tmpfilessystemd-tmpfiles-clean.service load…

TDengine 集群能力:超越 InfluxDB 的水平扩展与开源优势

随着物联网、车联网等领域的快速发展&#xff0c;企业所面临的数据采集量呈爆炸式增长&#xff0c;这对 IT 基础设施和数据库提出了严峻挑战。传统单机版数据库逐渐无法应对高并发的数据写入和复杂的查询需求。因此&#xff0c;底层数据库必须具备水平扩展能力&#xff0c;以确…

DAY23|回溯算法Part02|LeetCode: 39. 组合总和 、40.组合总和II 、131.分割回文串

目录 LeetCode: 39. 组合总和 基本思路 C代码 LeetCode: 40.组合总和II 基本思路 C代码 LeetCode: 131.分割回文串 基本思路 C代码 LeetCode: 39. 组合总和 力扣代码链接 文字讲解&#xff1a;LeetCode: 39. 组合总和 视频讲解&#xff1a;带你学透回溯算法-组合总和…

selenium大量并发连接驱动超时

我的业务是根据数据生成一大片报表图&#xff0c;组成一个word文档&#xff0c;量大概10~100之间&#xff0c;挨个执行太慢了&#xff0c;15分钟左右&#xff0c;为了加快速度使用了多线程&#xff0c;而多线程又被机器速度限制&#xff0c;一旦跑的多了&#xff0c;就会有线程…

【linux】再谈网络基础(二)

8. 再谈端口号 &#xff08;一&#xff09;与协议之间的关系 端口号(Port)标识了一个主机上进行通信的不同的应用程序 在TCP/IP协议中, 用 "源IP", "源端口号", "目的IP", "目的端口号", "协议号" 这样一个五元组来标识…

OpenCV视觉分析之目标跟踪(12)找到局部的最大值函数meanShift()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在反向投影图像上找到一个对象。 meanShift 是一种用于图像处理和计算机视觉领域的算法&#xff0c;特别适用于目标跟踪、图像分割等任务。该算…

VS2022配置OpenGL

下载地址&#xff1a; https://download.csdn.net/download/hgaohr1021/89974202 1、下载后&#xff0c;直接把OpenGL文件&#xff0c;全部放在 D:\Program Files这里&#xff0c;OpenGL这个名字也不要改&#xff01;&#xff01;&#xff01; 2、把文件PropertySheetOpenGL.p…

nvlink 训练笔记

目录 还没测试出效果 还没测试出效果 import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision.datasets import CIFAR10 from torchvision.transforms import ToTensor# 定义上述的大型全连接层模型 class LargeFullyConnectedModel(…

美术资源规范

很多项目都没有重视资源规范&#xff0c;而是不断追求更高的运行效率。然而资源规范在项目中是非常重要的&#xff0c;资源规范才是高效运行的前提。 在有的项目中&#xff0c;一个人物模型几万个面、一个建筑模型就几十万个面&#xff0c;贴图也不规范&#xff0c;1024、2048…

革命性AI搜索引擎!ChatGPT最新功能发布,无广告更智能!

文章目录 零、前言一、ChatGPT最新AI搜索引擎功能操作指导实战1:搜索新闻实战2:搜索天气实战3:搜索体育消息 二、感受 零、前言 大人&#xff0c;时代变了。 最强 AI 助力下的无广告搜索引擎终于问世。我们期待已久的这一刻终于到来了&#xff0c;从今天起&#xff0c;ChatGPT…

在 Ubuntu 上安装 Redis 并为其设置登录密码

在 Ubuntu 上安装 Redis 并为其设置密码 在 Ubuntu 上安装 Redis 并为其设置密码1. 更新包索引2. 安装 Redis3. 配置 Redis 密码4. 配置 Redis 以使用 systemd5. 启动 Redis 服务6. 检查 Redis 状态7. 测试 Redis8. 配置防火墙&#xff08;可选&#xff09;完成 在 Ubuntu 上安…

微积分复习笔记 Calculus Volume 1 - 4.10 Antiderivatives

4.10 Antiderivatives - Calculus Volume 1 | OpenStax

echarts设置tooltip宽高

ECharts容器&#xff1a; 1&#xff0c;ECharts容器设置宽度width&#xff0c;值可以是百分比或者是像素&#xff0c;当设置为百分比时&#xff0c;要检查父元素是否设置了宽度。注意&#xff1a;容器宽度设置不要用min-width&#xff0c;不然会发现tooltip的宽度等于min-widt…

kafka生产消费问题

一、kafka生产问题 1.漏发 生产者发送时候 有可能节点突然挂掉,send返回future,get(),同步发送,还可以在pro设置重试次数来容错,可以在失败时候,存储到哪里,另一个线程补发,不影响主流程 2.broker数据同步 broker里也可能出现问题,acks设置all,保证所有副本也收到消息 二、…

O-RAN Fronthual CU/Sync/Mgmt 平面和协议栈

O-RAN Fronthual CU/Sync/Mgmt 平面和协议栈 O-RAN Fronthual CU/Sync/Mgmt 平面和协议栈O-RAN前端O-RAN 前传平面C-Plane&#xff08;控制平面&#xff09;&#xff1a;控制平面消息定义数据传输、波束形成等所需的调度、协调。U-Plane&#xff08;用户平面&#xff09;&#…