【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…

C++并发编程之多线程环境下使用无锁数据结构的重要准则

在多线程环境中使用无锁数据结构&#xff08;Lock-Free Data Structures&#xff09;能够显著提高程序的并发性能&#xff0c;因为它们避免了传统锁机制带来的竞争和阻塞问题。然而&#xff0c;无锁编程本身也带来了许多挑战&#xff0c;如内存管理、数据一致性和正确性等问题。…

centos 8 中安装Docker

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

实现类似Excel的筛选

以下是在 DataGridView 中实现类似 Excel 下拉筛选功能的解决方案&#xff1a; 解决思路 为 DataGridView 的列添加 DataGridViewComboBoxColumn 类型的列&#xff0c;用于显示下拉筛选列表。为 DataGridView 的 ColumnHeaderMouseClick 事件添加处理程序&#xff0c;当用户点…

如何在 CentOS 中生成 CSR

在本教程中&#xff0c;我们将向您展示如何在CentOS 7和6中生成CSR。您可以直接从服务器生成 CSR。 只需按照以下步骤操作&#xff1a; 第 1 步&#xff1a;使用安全外壳 &#xff08;SSH&#xff09; 登录您的服务器 步骤 2&#xff1a;创建私钥和 CSR 文件 在提示符处键入以…

️ 如何将 Julia 包切换为本地开发版本?以 Reactant 为例

你是否正在开发一个 Julia 包&#xff0c;并希望将其从官方版本切换为本地开发版本&#xff1f;&#x1f914; 本文将手把手教你如何实现这一操作&#xff0c;并介绍一些实用技巧&#xff0c;让你的开发过程更加高效&#xff01;&#x1f680; &#x1f4cb; 准备工作 在开始之…

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

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

深入了解 alias 命令

1、alias简介 在 Unix 和类 Unix 系统中&#xff0c;alias&#xff08;别名&#xff09;是一个非常实用的命令&#xff0c;它允许用户为常用的命令设置简短的别名&#xff0c;从而减少重复输入复杂命令的时间&#xff0c;提高工作效率。尤其是在命令行操作中&#xff0c;alias…

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 一、…

MERN全栈脚手架(MongoDB、Express、React、Node)与Yeoman详解

MERN 全栈脚手架是一种用于快速构建基于 MongoDB、Express、React 和 Node.js 的全栈应用的框架或模板。它帮助开发者快速启动项目&#xff0c;减少了从零开始配置的时间。以下是关于 MERN 全栈脚手架的详细解析。 一、MERN 技术栈简介 MongoDB: 文档型数据库&#xff0c;用于…

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

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

【进程与线程】进程的PID

什么是 PID&#xff1f; PID&#xff08;Process Identifier&#xff0c;进程标识符&#xff09;是操作系统为每个进程分配的一个唯一标识&#xff0c;用于标识系统中的每个进程。PID 是一个非负整数&#xff0c;通常从 1 开始分配&#xff1b;每个运行中的进程都有一个唯一的…

学习python类的总结

前言 之前天天看到有人用类相关的知识但是学校老师就是没讲过&#xff0c;然后再读了莫烦老师的讲解后&#xff0c;有了一定的了解&#xff0c;进行一个总结。 正文 类的意义 类其实就是正如他的名字一样&#xff0c;是一类事物&#xff08;其实叫做对象&#xff09;的总称…

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、替…