【C语言】线程

目录

1. 什么是线程

1.1概念

1.2 进程和线程的区别

1.3 线程资源

2. 函数接口

2.1创建线程: pthread_create

2.2 退出线程: pthread_exit

2.3 回收线程资源

练习


1. 什么线程

1.1概念

线程是一个轻量级的进程,为了提高系统的性能引入线程。

在同一个进程中可以创建的多个线程, 共享进程资源。

线程和进程都参与统一的调度。

Linux里同样用task_struct来描述一个线程。

1.2 进程和线程的区别

相同点:都为操作系统提供了并发执行能力

不同点:

调度和资源:线程是系统调度的最小单位,进程是资源分配的最小单位。

地址空间方面:同一个进程创建的多个线程共享进程的资源;进程的地址空间相互独立

通信方面:线程通信相对简单,只需要通过全局变量可以实现,但是需要考虑临界资源访问的问题;进程通信比较复杂,需要借助进程间的通信机制(借助3g-4g内核空间)

安全性方面:线程安全性差一些,当进程结束时会导致所有线程退出;进程相对安全

程序什么时候该使用线程?什么时候用进程?

对资源的管理和保护要求高,不限制开销和效率时,使用多进程。

要求效率高、速度快的高并发环境时,需要频繁创建、销毁或切换时,资源的保护管理要求不是很高时,使用多线程。

1.3 线程资源

共享的资源:可执行的指令、静态数据、进程中打开的文件描述符、信号处理函数、当前工作目录、用户ID、用户组ID

私有的资源:线程ID (TID)、PC(程序计数器)和相关寄存器、堆栈(局部变量, 返回地址)、错误号 (errno)、信号掩码和优先级、执行状态和属性

2. 函数接口

2.1创建线程: pthread_create

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
功能:创建线程
参数:       thread:线程标识attr:线程属性, NULL:代表设置默认属性start_routine:函数名:代表线程函数(自己写的)arg:用来给前面函数传参
返回值:成功:0失败:错误码编译的时候需要加 -pthread 链接动态库

函数指针定义格式:数据类型 (* 指针名)(参数列表);

函数指针的例子:

#include <stdio.h>
#include <stdlib.h>
int test(int (*p)(int, int), int a, int b)
{return p(a,b);
}
int fun(int n, int m)
{return n * m;
}int main(int argc, char const *argv[])
{printf("%d\n", test(fun, 3, 4));return 0;
}

创建多线程:

#include<stdio.h>
#include<pthread.h>void *handler_thread(void *arg)
{printf("in handler_thread\n");while(1);   //让线程不退出,也就是多线程,进程状态为lreturn NULL;
}int main(int argc, char const *argv[])
{pthread_t tid;if(pthread_create(&tid,NULL,handler_thread,NULL) != 0){perror("create err");return -1;}printf("in main\n");while(1);   //让主线程也不退出return 0;
}

2.2 退出线程: pthread_exit

int  pthread_exit(void *value_ptr) 功能:用于退出线程的执行
参数:value_ptr:线程退出时返回的值
返回值:成功 : 0失败:errno

退出从线程:

#include <stdio.h>
#include <pthread.h>void *handler_thread(void *arg)
{printf("in handler_thread\n");pthread_exit(NULL);    //退出从线程while (1); //让线程不退出,也就是多线程return NULL;
}int main(int argc, char const *argv[])
{pthread_t tid;if (pthread_create(&tid, NULL, handler_thread, NULL) != 0){perror("create err");return -1;}printf("in main\n");while (1); //让主线程也不退出return 0;
}

2.3 回收线程资源

int  pthread_join(pthread_t thread,  void **value_ptr) 功能:用于等待一个指定的线程结束,阻塞函数
参数:thread:创建的线程对象,线程IDvalue_ptr:指针*value_ptr指向线程返回的参数, 一般为NULL
返回值:成功 : 0失败:errnoint pthread_detach(pthread_t thread);
功能:让线程结束时自动回收线程资源,让线程和主线程分离,非阻塞函数
参数:thread:线程ID
非阻塞式的,例如主线程分离(detach)了线程T2,那么主线程不会阻塞在pthread_detach(),pthread_detach()会直接返回,线程T2终止后会被操作系统自动回收资源
#include <stdio.h>
#include <pthread.h>void *handler_thread(void *arg)
{printf("in handler_thread\n");pthread_exit(NULL);return NULL;
}int main(int argc, char const *argv[])
{pthread_t tid;if (pthread_create(&tid, NULL, handler_thread, NULL) != 0){perror("create err");return -1;}pthread_join(tid, NULL); //阻塞函数,阻塞等待着从线程退出并回收线程资源。printf("in main\n");return 0;
}

练习

1. 通过父子进程完成对文件的拷贝(cp),父进程从文件开始到文件的一半开始拷贝,子进程从文件的一半到文件末尾。要求:文件IO cp src dest

1) 文件长度获取?lseek

2) 子进程定位到文件一半的位置 lseek

3) 父进程怎么能准确读到文件一半的位置

4) fork之前打开文件,父子进程中读写文件时,位置指针是同一个

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>int main(int argc, char const *argv[])
{pid_t pid;int fd_src, fd_dest;ssize_t s;char buf[32] = "";if (argc != 3){printf("Usage: %s <strcfile> <destfile>\n", argv[0]);return -1;}fd_src = open(argv[1], O_RDONLY);if (fd_src < 0){perror("open src err");return -1;}fd_dest = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);if (fd_dest < 0){perror("open dest err");return -1;}//计算出一半的长度off_t len = lseek(fd_src, 0, SEEK_END) / 2;//创建子进程pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) //子进程,从一半到末尾{printf("child\n");//子进程定位到一半开始读lseek(fd_src, len, SEEK_SET);lseek(fd_dest, len, SEEK_SET);while (1){//读写if ((s = read(fd_src, buf, 32)) == 0)break;write(fd_dest, buf, s);}}else //父进程,从开始到一半{printf("parent\n");wait(NULL);//父进程定位到开头lseek(fd_src, 0, SEEK_SET);lseek(fd_dest, 0, SEEK_SET);while (len > 0) //父进程从文件开始读写到一半,利用让len减少到0就停止读写。{if (len > 32) //不是读最后一次s = read(fd_src, buf, 32);else //读最后一次(可能)s = read(fd_src, buf, len); //如果也设32,那么有可能最后一次会多读而不是恰好读一半write(fd_dest, buf, s);len -= s; //剩下的要读的字符个数}}close(fd_src);close(fd_dest);return 0;
}

避免父子进程一起读取和写入操作导致混乱,可以用阻塞函数,先让子进程读写完了再让父进程读写。

2. 通过线程实现数据的交互,主线程循环从终端输入,线程函数将数据循环输出,当输入quit结束程序。

#include <stdio.h>
#include <pthread.h>
#include <string.h>char s[32];
int flag = 0; //为了进行线程间通讯,保证主线程先执行输入操作,然后从线程再输出。
void *handler_thread(void *arg)
{while (1){if (flag == 1){if (strcmp(s, "quit") == 0)break;printf("%s\n", s);flag = 0;}}return NULL;
}int main(int argc, char const *argv[])
{pthread_t tid;if (pthread_create(&tid, NULL, handler_thread, NULL) != 0){perror("err");return -1;}while (1){scanf("%s", s);flag = 1;if (strcmp(s, "quit") == 0)break;}return 0;
}

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

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

相关文章

【C语言】字符串函数详解

文章目录 Ⅰ. strcpy -- 字符串拷贝1、函数介绍2、模拟实现 Ⅱ. strcat -- 字符串追加1、函数介绍2、模拟实现 Ⅲ. strcmp -- 字符串比较1、函数介绍2、模拟实现 Ⅳ. strncpy、strncat、strncmp -- 可限制操作长度Ⅴ. strlen -- 求字符串长度1、函数介绍2、模拟实现&#xff08…

Windows部署NVM并下载多版本Node.js的方法(含删除原有Node的方法)

本文介绍在Windows电脑中&#xff0c;下载、部署NVM&#xff08;node.js version management&#xff09;环境&#xff0c;并基于其安装不同版本的Node.js的方法。 在之前的文章Windows系统下载、部署Node.js与npm环境的方法&#xff08;https://blog.csdn.net/zhebushibiaoshi…

centos 8 中安装Docker

注&#xff1a;本次样式安装使用的是centos8 操作系统。 1、镜像下载 具体的镜像下载地址各位可以去官网下载&#xff0c;选择适合你们的下载即可&#xff01; 1、CentOS官方下载地址&#xff1a;https://vault.centos.org/ 2、阿里云开源镜像站下载&#xff1a;centos安装包…

STM32-笔记40-BKP(备份寄存器)

一、什么是BKP&#xff08;备份寄存器&#xff09;&#xff1f; 备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份域里&#xff0c;当VDD电源被切断&#xff0c;他们仍然由VBAT维持供电。当系统在待机模式下被唤醒&#xff0c;或…

vue-cli项目配置使用unocss

在了解使用了Unocss后&#xff0c;就完全被它迷住了。接手过的所有项目都配置使用了它&#xff0c;包括一些旧项目&#xff0c;也跟同事分享了使用Unocss的便捷性。 这里分享一下旧项目如何配置和使用Unocss的&#xff0c;项目是vue2vue-cli构建的&#xff0c;node<20平常开…

新增文章分类功能

总说 过程参考黑马程序员SpringBoot3Vue3全套视频教程&#xff0c;springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 目录 总说 一、功能实现 1.1 Controller层 1.2 Service层 1.3 Impl层 1.4 Mapper层 1.5 测试接口 二、优化 2.1 2.2 一、…

知识图谱常见的主流图数据库

在知识图谱中&#xff0c;主流使用的图数据库包括以下几种&#xff1a; Neo4j&#xff1a;这是目前全球部署最广泛的图数据库之一&#xff0c;具有强大的查询性能和灵活的数据模型&#xff0c;适用于复杂关系数据的存储和查询。 JanusGraph&#xff1a;JanusGraph是一个开源的…

JavaSE学习心得(多线程与网络编程篇)

多线程-网络编程 前言 多线程&JUC 多线程三种实现方式 第一种实现方式 第二种实现方式 第三种实现方式 常见成员方法 买票引发的安全问题 同步代码块 同步方法 Lock锁 生产者和消费者 常见方法 等待唤醒机制 练习 抢红包 抽奖 多线程统计并求最…

Pytorch基础教程:从零实现手写数字分类

文章目录 1.Pytorch简介2.理解tensor2.1 一维矩阵2.2 二维矩阵2.3 三维矩阵 3.创建tensor3.1 你可以直接从一个Python列表或NumPy数组创建一个tensor&#xff1a;3.2 创建特定形状的tensor3.3 创建三维tensor3.4 使用随机数填充tensor3.5 指定tensor的数据类型 4.tensor基本运算…

candb++ windows11运行报错,找不到mfc140.dll

解决问题记录 mfc140.dll下载 注意&#xff1a;放置位置别搞错了

​公专网一体5G工业路由器,智慧电网全链路加密监控管理

随着可再生能源的集成 电网调度策略复杂性增加 需更精细的并网管理以平衡供需 传统电力网络的通信基础落后 难以适应电力设施的广泛分布 和日益增长的管理维护需求 计讯物联5G公专网一体路由器 通过融合公网和专网的优势 有效解决了现代电网对于 高效、灵活和安全通信的需求 ↓…

【Linux】--- 进程的等待与替换

进程的等待与替换 一、进程等待1、进程等待的必要性2、获取子进程status3、进程等待的方法&#xff08;1&#xff09;wait&#xff08;&#xff09;函数&#xff08;2&#xff09;waitpid函数 4、多进程创建以及等待的代码模型5、非阻塞接口 轮询 二、进程替换1、替换原理2、替…

zerotier搭建虚拟局域网,自建planet

基于该开源项目 自建planet节点&#xff0c;更快速&#xff0c;更安全 本教程依据docker-zerotier-planet 项目文档书写&#xff0c;并以linux(centos 7)和windows作为示例&#xff0c;需要其他系统配置方法&#xff0c;可移步项目文档 一. 前置资源 具有外网ip的服务器 后面…

屏幕轻触间:触摸交互从 “感知” 到 “智算” 的隐秘路径

从用户点击屏幕到前端感知及数据处理全流程剖析 引言 在移动智能设备与触摸交互技术深度融合的当下&#xff0c;当我们的手指轻触手机屏幕&#xff0c;一系列复杂且精妙的技术流程便瞬间启动。这一过程涵盖硬件层、驱动层、操作系统层、应用层&#xff0c;甚至延伸到后端的数…

深入Node.js集群:原理、优势与搭建实战,如何应对高并发

文章目录 一、Node.js 集群简介二、Node.js 集群原理剖析2.1 主从模型2.2 负载均衡机制2.3 进程间通信&#xff08;IPC&#xff09; 三、Node.js 集群优势详解3.1 性能提升3.2 高可用性3.3 资源利用率优化 四、Node.js 集群搭建实战4.1 准备工作4.2 创建主控制节点4.3 工作节点…

数字普惠金融对新质生产力的影响研究(2015-2023年)

基于2015—2023年中国制造业上市公司数据&#xff0c;探讨了数字普惠金融对制造业企业新质生产力的影响及作用机理。研究发现&#xff0c;数字普惠金融有助于促进制造业企业新质生产力的发展&#xff0c;尤其是在数字普惠金融的使用深度较大的情况下&#xff0c;其对新质生产力…

数据仓库基础常见面试题

1.数据仓库是什么 ‌数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的、集成的、非易失的、随时间变化的数据集合&#xff0c;用于支持企业的管理决策‌。它不同于传统的操作型数据库&#xff0c;后者主要用于处理日常业务交易和实时查询&#xff0c;而数据仓库…

记一次OpenEuler Linux磁盘分区表损坏的数据恢复

问题复现 原本有一台GIS地图服务器存放大量数据&#xff0c;突然有一天磁盘满了&#xff0c;于是运维人员照常进行磁盘扩容。但由于误操作&#xff0c;导致使用fdisk的时候把分区表损坏了&#xff0c;表现如下&#xff1a; 这里可以看到启动时能看到xvda被分为了xvda1和xvda2…

分布式数据存储基础与HDFS操作实践(副本)

以下为作者本人撰写的报告&#xff0c;步骤略有繁琐&#xff0c;不建议作为参考内容&#xff0c;可以适当浏览&#xff0c;进一步理解。 一、实验目的 1、理解分布式文件系统的基本概念和工作原理。 2、掌握Hadoop分布式文件系统&#xff08;HDFS&#xff09;的基本操作。 …

APP推荐:全新TV端来了,8K原画电视版

▌ 软件介绍 B站都不陌生吧&#xff0c;一个能追番、学习、娱乐的多元平台&#xff0c;之前也分享过几款第三方TV端&#xff0c;其中的BV最近更新了全新版本。 使用了全新的UI界面&#xff0c;由之前的顶部菜单栏改成了侧边布局&#xff0c;已解锁限制&…