05.线程

news2024/12/29 8:49:10

进程有哪些缺陷?

1.创建的代价较高

进程是OS进行资源分配的基本单位,也就是说创建进程是需要分配资源的,所以创建代价很高

2.通信不方便

进程之间要想进行通信必须借助第三方资源(管道、内存映射、消息队列)

线程的优点有哪些?

线程与进行一样,在单核的情情况下都可以并发执行,多核可以并行执行。
但是线程的创建代价没有进程高,一个进程可以创建多个线程,这写线程共享同一份资源。共享同一份资源自然,通信就方便了很多

pthread_create函数

创建线程的函数

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,(void *)( *start_routine)(void *),void *arg)

参一:传出参数,子线程tid
参二:线程的属性(attr)
参三:函数指针,子进程要执行的代码放在这个函数里面
参四:子进程函数的参数
返回值:
成功返回0
失败返回错误号
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
void* thread1(void* arg){
    sleep(1);
    printf("thread1 = %lu\n",pthread_self());
    return NULL;
}

int main(int argc, char* argv[])
{
    pthread_t tid;
    int ret = pthread_create(&tid,NULL,thread1,NULL);
    if(ret == -1){
        perror("pthread_create error:");
        return -1;
    }
    printf("main therad = %lu\n",pthread_self());
    //%lu是无符号场整形 unsigned long int 
    while(1);
    return 0;
}

pthread_self函数

获取线程tid的函数

pthread_t pthread_self(void)

返回值和无符号场整形,%lu
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
int a;
void* thread1(void* arg){
    printf("thread1 tid = %lu\n",pthread_self());
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        sleep(1);
    }
    return NULL;
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    int ret = pthread_create(&tid,NULL,thread1,NULL);
    if(ret != 0){
        perror("pthread_create error:");
        return -1;
    }
    printf("main thread tid = %lu\n",pthread_self());
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        sleep(1);
    }
    printf("pthread_create ret = %d\n",ret);
    return 0;
}

终止线程的方法

1.进程结束了,底下的线程肯定都结束了

在主函数执行return

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
int a;
void* thread1(void* arg){
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        sleep(1);
    }
    return NULL;
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread1,NULL);
    sleep(1);
    return 0;
}

调用exit()函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void* thread1(void* arg){
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        sleep(1);
    }
    return NULL;
}
void* thread2(void* arg){
    sleep(2);
    exit(-1);
    return NULL;
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread1,NULL);
    pthread_create(&tid,NULL,thread2,NULL);
    while(1);
    return 0;
}

2.结束当前的线程

在start_rountine函数中执行return

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void* thread1(void* arg){
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        return NULL;
        printf("1\n");
    }
    
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread1,NULL);
    sleep(2);
    return 0;
}

调用pthread_exit()函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void func(){
    printf("This is func!\n");
    pthread_exit(NULL);
}
void* thread1(void* arg){
    while(a!=10){
        a++;
        printf("a = %d\n",a);
        func();
        printf("1\n");
    }
    
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread1,NULL);
    sleep(2);
    return 0;
}

调用pthread_cancel函数

int pthread_cancel(pthread_t thread);
参一为要取消的线程
函数描述:调用该函数之后,会向指定线程发送一个取消请求,然后立即返回,被请求取消的进程需要等到某个取消点(通常为系统调用)
可以调用pthread_testcancel()函数,手动创建取消点
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
int stats;

void* thread1(void* arg){
    while(1){
        if(a == 10){
            a=0;
        }
        a++;
        pthread_testcancel();
    }
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    pthread_create(&tid,NULL,thread1,NULL);
    int ret = pthread_cancel(tid);
    if(ret == 0){
        printf("cancel sucess!\n");
    }else{
        printf("cancel error!\n");
    }
    while(1){
        printf("a = %d\n",a);
        sleep(1);
    }
    return 0;
}

线程的连接和分离

pthread_join函数

函数原型:int pthread_join(pthread_t tid ,void **retval);

函数描述:等待指定线程的结束,然后回收,这种操作被称为连接。未连接的进程会产生僵尸线程

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;

void* thread1(void* arg){
    while(1){
        if(a == 10){
            pthread_exit(NULL);
        }
        a++;
    }
}
int main(int argc, char* argv[])
{
    pthread_t tid;
    void* res;
    pthread_create(&tid,NULL,thread1,NULL);
    pthread_join(tid,&res);
    printf("res = %s",(char*)res);
    printf("a = %d\n",a);
    return 0;
}

有些线程不关心返回状态,只是希望OS能在线程终止的时候自动清理并移出,这时可以调用pthread_detach函数设置线程未分离状态

pthread_detach函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;

void* thread1(void* arg){
    while(1){
        if(a == 10){
            pthread_exit(NULL);
        }
        a++;
    }
}
void* thread2(void* arg){
    while(1){
        if(a == 10){
            pthread_exit(NULL);
        }
        a++;
    }
}
int main(int argc, char* argv[])
{
    pthread_t tid1;
    pthread_t tid2;
    void* res;
    pthread_create(&tid1,NULL,thread1,NULL);
    pthread_create(&tid2,NULL,thread2,NULL);
    pthread_detach(tid2);
    pthread_join(tid2,&res);
    printf("res = %s",(char*)res);
    printf("a = %d\n",a);
    return 0;
}

练习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
const int N=1e6;
int a;
void* thread1(void* arg){
    for(int i = 1;i <= N; i++){
        a++;
    }
}
int main(int argc, char* argv[])
{
    pthread_t tids[10];
    //创建10个线程,用tids数组存储tid
    for(int i = 0;i < 10; i++){
        pthread_create(tids+i,NULL,thread1,NULL);
    }
    //阻塞等待10个线程都执行结束,打印a的值
    for(int i = 0;i < 10; i++){
        pthread_join(tids[i],NULL);
    }
    printf("a = %d\n",a);
    return 0;
}

观察数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

线程同步的引入

观察上面的数据,发现10个线程如果同时执行1e6次自增操作,最后结果应该是1e7,但是多次得到的结果确实小于等于1e7,这种情况是不可以接受的,为什么会出现这种问题?

因为线程之间的并发执行的,且a++不是原子操作。
举一个例子,现在线程1和线程2并发执行,它们同时读取了a的数据,读到的都是5,然后对5+1返回结果给a,线程1和线程2同时结束,a的值为6,而不是7,这就出现了问题。出现这个问题的原因是线程之间是共享资源的,同时访问一块内存,有时会造成错误。(保证线程和线程访问同一块空间的时候不出现冲突)
所以得让进程之间商量着来,协同一下步调。

同步

同步分为同步异步的同步和线程同步

同步与异步

提到同步和异步,很难不想到阻塞和非阻塞。

阻塞和非阻塞一半表述进程的状态,具体指的是进程在执行过程中是否遇到阻塞实现(是否被挂起),如果被挂起了就是阻塞状态,没有被挂起就是非阻塞

而同步异步一般指的是系统调用时候是否会阻塞执行

同步函数

同步函数是指在系统调用的过程中,程序会被阻塞,知道系统调用结束返回结果。
特点:
1.阻塞执行
2.可预测,符合传统程序的执行过程

异步函数

异步函数指的是系统调用过程中,程序不会阻塞,继续执行后面的代码。等到系统调用结束之后,内核会通过某种机制(信号或者回调函数等等)通知程序。
特点:
1.非阻塞:不会阻塞等待返回的结果,而是直接执行后面的代码。
2.事件驱动性:当系统调用完成时,内核会通过事件通知应用程序,应用程序需要处理这些事件
3.复杂性:异步编程模型复杂,需要处理多个事件和状态

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

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

相关文章

在线教程|二次元的福音!一键部署APISR,动漫画质飞跃升级

从守护城市安全的「火眼金睛」&#xff0c;到探索人体奥秘的医学之窗&#xff0c;再到娱乐产业的视觉盛宴&#xff0c;乃至遥望宇宙的卫星视角&#xff0c;超分辨率技术重塑着我们观察世界的新维度&#xff0c;让每一寸画面绽放前所未有的清晰与真实。 近年来&#xff0c;越来…

【C++】C++中的template模板

一、泛型编程 关于模板的出现其实是在广大程序员编程中偷懒省下来的。我举个例子你们就知道了。 下述例子是用来实现swap函数的&#xff0c;利用的方式是最基础的重载。 void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(d…

【Linux操作系统】:文件操作

目录 前言 一、C语言中文件IO操作 1.文件的打开方式 2.fopen&#xff1a;打开文件 3.fread&#xff1a;读文件 4.fwrite:写文件 二、系统文件I/O 1.系统调用open、read、write 2.文件描述符fd 3.文件描述符的分配规则 4.重定向 5.缓冲区 6.理解文件系统 磁盘 磁盘…

掌握这几点,稳稳拿下中质协六西格玛考试!

在当今竞争激烈的市场环境中&#xff0c;拥有六西格玛证书无疑是提升自身职业竞争力的一大利器。中质协作为权威机构&#xff0c;其六西格玛考试更是备受关注。那么&#xff0c;如何才能稳稳拿下这场考试呢&#xff1f;深圳天行健六西格玛管理培训公司有建议如下&#xff1a; 一…

【计算机毕业设计】springboot国风彩妆网站

二十一世纪我们的社会进入了信息时代&#xff0c; 信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…

影刀进行shopee商品排名零代码爬取

需要研究shopee平台的排名更新时间段和周期&#xff0c;几分钟用影刀写了一个爬取应用&#xff0c;每10分钟进行一次排名爬取&#xff08;以fan‘风扇’为例&#xff09;&#xff0c;0代码爬取。 打开’fan’关键词搜索网页&#xff1b;等待网页加载&#xff1b;滚动进一步加载…

计算机服务器中了devicdata勒索病毒如何解密,devicdata勒索病毒解密恢复工具

在网络技术飞速发展的时代&#xff0c;有效地利用网络开展各项工作业务&#xff0c;能够大大提升企业的生产运行效率&#xff0c;改善企业的发展运营模式&#xff0c;但如果网络利用不好就会给企业的数据安全带来严重威胁。近日&#xff0c;云天数据恢复中心接到很多企业的求助…

复制粘贴插件——clipboard.js的使用

clipboard.js是一款使用简单的粘贴复制插件,它不依赖于Flash或其他框架&#xff0c;在github拥有3万多颗星可见其优秀程度&#xff0c;介绍如何使用它&#xff0c;以备存。 中文文档&#xff1a; clipboard.js 中文文档 - itxst.com 官网网站&#xff1a;https://github.com/…

【C++】 类的6个默认成员函数

目录 1. 类的6个默认成员函数 一.构造函数 1.基本概念 2 特性 注意&#xff1a;C11 中针对内置类型成员不初始化的缺陷&#xff0c;又打了补丁&#xff0c; 3.构造函数详解 3.1构造函数体赋值 3.2 初始化列表 3.3 explicit关键字 二.析构函数 1 概念 2 特性 两个栈实…

安装vmware station记录

想学一下linux,花了3个多小时&#xff0c;才配置好了&#xff0c;记录一下 安装vm12,已配置linux系统 报错&#xff0c;VMware Workstation 与 Device/Credential Guard 不兼容解决方案&#xff0c;网上说有不成功的&#xff0c;电脑蓝屏&#xff0c;选择装vm16试试 vm16 在…

多个.C文件被编译为一个可执行文件的详细过程

多个.C文件被编译为一个可执行文件的详细过程 文章目录 多个.C文件被编译为一个可执行文件的详细过程前言一、一个.C文件的编译过程二、多个.C文件的链接过程1.文件信息2.链接过程3.makefile 总结 前言 C语言经典的 “hello world ” 程序从编写、编译到运行&#xff0c;看到屏…

electron-vite工具打包后通过内置配置文件动态修改接口地址实现方法

系列文章目录 electronvitevue3 快速入门教程 文章目录 系列文章目录前言一、实现过程二、代码演示1.resources/env.json2.App.vue3.main/index.js4.request.js5.安装后修改 前言 使用electron-vite 工具开发项目打包完后每次要改接口地址都要重新打包&#xff0c;对于多环境…

揭秘Ping32如何实现上网行为监控

企业上网行为管理软件在现代企业管理中扮演着举足轻重的角色。它不仅能够监控和记录员工的上网行为&#xff0c;还能有效防止数据泄露和不当使用&#xff0c;从而保障企业的信息安全。 一、Ping32上网监控软件的具体功能包括&#xff1a; 1.网页浏览监控&#xff1a;对Chrome…

[C++核心编程-06]----C++类和对象之对象模型和this指针

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

文心一言 VS 讯飞星火 VS chatgpt (255)-- 算法导论18.3 1题

一、请说明依次从图18-8(f)中删除C、P和V后的结果。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 首先&#xff0c;让我们明确一点&#xff1a;由于您没有提供具体的图18-8(f)的内容&#xff0c;我只能假设它是一个数据结构&#xff08;可能是图、树或列表等&…

【spring】Security 密码加密算法

Spring Security 提供了多种密码加密算法&#xff0c;用于在存储用户密码时进行加密&#xff0c;以增强安全性。 查看org.springframework.security.crypto.factory.PasswordEncoderFactories 以下是一些常用的密码加密算法&#xff1a; BCryptPasswordEncoder&#xff1a; 这…

白酒:酒精度数与白酒品质消费的关联性研究

酒精度数作为白酒的一项重要指标&#xff0c;不仅影响着白酒的口感和风格&#xff0c;更在很大程度上与白酒的消费存在密切关联。在探讨云仓酒庄豪迈白酒时&#xff0c;我们不能忽视酒精度数与品质消费之间的关联性。 首先&#xff0c;酒精度数的高低直接影响到白酒中酒精的含量…

企业活动想联系媒体报道宣传如何联系媒体?

在企业的宣传推广工作中,我曾经历过一段费事费力、效率极低的时期。那时,每当公司有重要活动或新项目需要媒体报道时,我便要一家家地联系媒体,发送邮件、打电话,甚至亲自登门拜访,只为求得一篇报道。然而,这样的过程充满了不确定性和挑战,时常让我感到焦虑和压力山大。 记得有一…

gif压缩大小但不改变画质怎么做?分享5个压缩GIF原理~

GIF&#xff08;图形互换格式&#xff09;是网络上广泛使用的一种图像格式&#xff0c;因其支持动画而备受欢迎。然而&#xff0c;随着动画越来越复杂和高分辨率&#xff0c;GIF 文件大小也随之增加&#xff0c;可能导致加载速度变慢和带宽消耗增加。在这篇文章中&#xff0c;我…

编程怎么学?踏上编程之旅:如何高效学习编程

编程怎么学&#xff1f;踏上编程之旅&#xff1a;如何高效学习编程 编程&#xff0c;作为数字时代的核心技能&#xff0c;正吸引着越来越多的人投身其中。然而&#xff0c;面对浩瀚的知识体系和纷繁的学习资源&#xff0c;初学者往往感到迷茫。本文将为你指引一条高效的编程学习…