Linux 【C编程】 引入线程,线程相关函数

news2024/11/13 14:54:06

1.线程的引入

1.1使用线程同时读取键盘和鼠标

代码演示:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
// 读取键盘输入的线程函数
void *keyboardThread(void *arg) {
    char c;
    while (1) {
        // 从键盘读取一个字符
        c = getchar();
        // 打印从键盘读取的字符
        printf("键盘输入: %c\n", c);
    }
}

int  main(){
    int ret = -1;
    int fd = -1;
    char buf[200];
    pthread_t th  =-1;
    //k开一个子线程
    ret = pthread_create(&th,NULL,keyboardThread,NULL);

    //主进程读取鼠标输入

    memset(buf,0,sizeof(buf));
    //读取鼠标
    fd = open("/dev/input/mouse0",O_RDONLY);
    if(fd<0){
        perror("open:");
        return -1;
    }

    while(1){
        read (fd,buf,2);  //从鼠标读取两位
        printf("mouse读出来的内容是 :【%s】\n",buf);
    }
 
    return 0;

}

效果如下:
在这里插入图片描述
需要注意到的一点是:
使用了pthread库,因此编译时需要链接 -lpthread

1.2Linux中线程简介

  • 在Linux系统中,线程是一种轻量级的执行单元,与进程共享相同的地址空间。
  • 一个进程中可以有多个线程
  • 线程是参与内核调度的最小单元

1.3线程技术的优势

  • 并发执行: 线程使得程序可以同时执行多个任务,从而提高了系统的并发性。这允许程序在某个线程等待I/O操作完成的同时,其他线程可以继续执行,提高了系统的利用率。

  • 资源共享: 线程之间共享同一进程的地址空间,可以更方便地共享数据。这样,多个线程可以访问和修改相同的变量,共享同一份代码和静态数据,减少了资源的冗余使用。

  • 轻量级: 相较于进程,线程是轻量级的执行单元。线程的创建、销毁和切换成本较低,因此在需要频繁创建和销毁执行单元的场景中,线程更为适用。

  • 响应性: 多线程可以使程序更加响应用户输入和事件。例如,在图形用户界面(GUI)应用程序中,一个线程可以负责用户界面的更新,而另一个线程可以处理用户输入,使得应用程序看起来更为流畅。

  • 模块化设计: 通过将不同的任务分配给不同的线程,可以实现模块化的程序设计。每个线程负责一个特定的功能或任务,使得代码更易于理解、维护和扩展。

  • 性能提升: 在多核处理器上,多线程程序可以更好地利用硬件资源,从而提高程序的性能。并行执行的线程可以在多个核心上同时运行,加速任务的完成。

  • 异步编程: 线程可以用于实现异步编程模型,通过在后台执行任务,使得程序能够继续执行其他操作。这对于需要处理I/O操作或等待外部事件的场景非常有用。

  • 实时性: 一些实时系统需要在特定时间内完成任务,线程可以用于实现对任务的及时响应,确保实时性要求得到满足。

2.线程中常见函数

2.1 线程创建与回收

  • pthread_create

    POSIX 线程库中用于创建新线程的函数。该函数的原型如下:

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine)(void*), void *arg);
  • thread:一个指向 pthread_t 类型的变量的指针,用于存储新线程的标识符。

  • attr:一个指向 pthread_attr_t 类型的变量的指针,用于设置新线程的属性,通常可以传入 NULL 以使用默认属性。

  • start_routine:是一个指向函数的指针,该函数定义了新线程的起始点。新线程将从这个函数开始执行。这个函数的签名应为 void* start_routine(void*)。

  • arg:是传递给 start_routine 函数的参数。

函数返回值为 0 表示成功创建新线程,非零值表示出现了错误。

  • pthread_join
    主线程等待(阻塞)回收子线程
#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);
  • thread:要等待的线程的标识符,通常由 pthread_create 返回得到。
  • retval:一个指向指针的指针,用于获取线程的返回值。如果不关心线程的返回值,可以将这个参数设置为 NULL。

可以说 pthread_create 与 pthread_join 成对出现的,一个负责创建一个负责回收
代码演示:

#include <stdio.h>
#include <pthread.h>

void *printMessage(void *arg) {
    char *message = (char *)arg;
    printf("%s\n", message);
    pthread_exit((void *)42);
}

int main() {
    pthread_t tid;
    char *message = "Hello from the new thread!";
    void *result;

    // 创建新线程
    int result_create = pthread_create(&tid, NULL, printMessage, (void *)message);
    if (result_create != 0) {
        fprintf(stderr, "Thread creation failed: %d\n", result_create);
        return 1;
    }

    // 等待新线程结束
    int result_join = pthread_join(tid, &result);
    if (result_join != 0) {
        fprintf(stderr, "Thread join failed: %d\n", result_join);
        return 1;
    }

    // 打印新线程的返回值
    printf("New thread returned: %ld\n", (long)result);

    return 0;
}
  • pthread_detach
    用于将一个线程标记为“分离状态”(detached state)。线程的分离状态决定了线程退出后系统是否会自动回收其资源。
int pthread_detach(pthread_t thread);

这个函数的参数 thread 是要分离的线程的标识符,通常由 pthread_create 返回得到。函数返回值为 0 表示成功,非零值表示出现了错误。
调用 pthread_detach 将线程标记为“分离状态”,这意味着线程结束后,系统会自动回收其资源。分离状态的线程不再需要主线程调用 pthread_join 来等待其结束,因为线程结束后,它的所有资源都会被自动回收。
一旦调用 pthread_detach 将线程标记为分离状态,就无法再将其改回非分离状态。这意味着在设置分离状态后,主线程无需显式等待该线程的结束。
代码演示:

#include <stdio.h>
#include <pthread.h>

void *printMessage(void *arg) {
    char *message = (char *)arg;
    printf("%s\n", message);
    pthread_exit(NULL);
}

int main() {
    pthread_t tid;
    char *message = "Hello from the detached thread!";

    // 创建新线程并设置为分离状态
    int result_create = pthread_create(&tid, NULL, printMessage, (void *)message);
    if (result_create != 0) {
        fprintf(stderr, "Thread creation failed: %d\n", result_create);
        return 1;
    }

    // 设置线程为分离状态
    int result_detach = pthread_detach(tid);
    if (result_detach != 0) {
        fprintf(stderr, "Thread detach failed: %d\n", result_detach);
        return 1;
    }

    // 主线程继续执行,不需要等待新线程结束

    return 0;
}

2.2线程取消

  • pthread_cancel
    用于请求取消另一个线程的执行。该函数的原型如下:
int pthread_cancel(pthread_t thread);

函数返回值为 0 表示成功发送取消请求,非零值表示出现了错误。

  • pthread_setcancelstate
    子线程设置自己是否可以被取消,新线程被创建之后,默认是可以被取消的
  • pthread_setcanceltype
    设置线程的取消类型。有两种类型:PTHREAD_CANCEL_DEFERRED 和 PTHREAD_CANCEL_ASYNCHRONOUS。前者表示线程将在取消点检查取消请求,后者表示线程将在任何时刻检查取消请求。默认情况下,取消类型是 PTHREAD_CANCEL_DEFERRED。

线程会在取消点检查取消请求。取消点是一些标准的库函数,例如 pthread_join、sleep 等。
线程在执行这些函数时,会检查是否有取消请求。
代码演示:

#include <stdio.h>
#include <pthread.h>

void *cancelExample(void *arg) {
    while (1) {
        printf("Thread is running...\n");
        sleep(1);  // 休眠是一个取消点
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t tid;

    // 创建新线程
    int result_create = pthread_create(&tid, NULL, cancelExample, NULL);
    if (result_create != 0) {
        fprintf(stderr, "Thread creation failed: %d\n", result_create);
        return 1;
    }

    // 主线程休眠一段时间后发送取消请求
    sleep(3);
    int result_cancel = pthread_cancel(tid);
    if (result_cancel != 0) {
        fprintf(stderr, "Thread cancel failed: %d\n", result_cancel);
        return 1;
    }

    // 主线程等待新线程结束
    pthread_join(tid, NULL);

    return 0;
}

2.3线程退出

  • pthread_exit
    pthread_exit 和 return 都用于结束线程的执行
void pthread_exit(void *retval);

pthread_exit 是一个线程库提供的函数,用于终止当前线程的执行。它可以传递一个指针作为线程的返回值,这个指针将被用作线程的退出状态。当调用 pthread_exit 时,线程的资源(如栈空间)不会被回收,需要通过其他线程调用 pthread_join 来等待并回收这个线程的资源。

  • pthread_cleanup_push
  • pthread_cleanup_pop
    pthread_cleanup_push 是 POSIX 线程库中的函数,用于将清理函数(cleanup handler)推入线程的清理处理栈。它通常与 pthread_cleanup_pop 配合使用,用于在线程退出时执行一些清理操作。
void pthread_cleanup_push(void (*routine)(void *), void *arg);

pthread_cleanup_push 将清理函数和参数推入线程的清理处理栈。在线程退出时,栈上的所有清理函数都会被依次执行。
代码演示:

#include <stdio.h>
#include <pthread.h>

void cleanupHandler(void *arg) {
    printf("Cleanup handler: %s\n", (char *)arg);
}

void *threadFunction(void *arg) {
    // 推入清理函数和参数到栈
    pthread_cleanup_push(cleanupHandler, "First cleanup");
    pthread_cleanup_push(cleanupHandler, "Second cleanup");

    // 线程的主要逻辑
    printf("Thread is running.\n");
    // 模拟线程取消点(Cancellation Point)
    sleep(2);

    // 弹出清理函数,但不执行
    pthread_cleanup_pop(0);
    // 弹出清理函数,并执行
    pthread_cleanup_pop(1);

    // 正常退出
    pthread_exit(NULL);
}

int main() {
    pthread_t tid;

    // 创建新线程
    int result_create = pthread_create(&tid, NULL, threadFunction, NULL);
    if (result_create != 0) {
        fprintf(stderr, "Thread creation failed: %d\n", result_create);
        return 1;
    }

    // 等待线程结束
    pthread_join(tid, NULL);

    return 0;
}

2.4获取线程ID

使用 pthread_self 函数来获取当前线程的线程标识符(Thread ID)。该函数的原型如下:


pthread_t pthread_self(void);

调用该函数就会返回调用线程的线程标识符

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

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

相关文章

可视化 | 【echarts】渐变条形+折线复合图

文章目录 &#x1f4da;html css&#x1f4da;js&#x1f407;总体框架&#x1f407;option配置项 &#x1f4da;html css html&#xff1a;在这主要是用于整合&#xff0c;将html、css、js连接在一块&#xff0c;虽然单个模板代码量不大&#xff0c;但还是先分开&#xff0…

AI嵌入式K210项目(13)-Camera

文章目录 前言一、硬件介绍二、K210对硬件的支持实验过程总结 前言 我们这款开发板应该是最便宜的AI开发板了吧&#xff0c;200RMB左右&#xff0c;搭载1TOPS处理能力的K210芯片&#xff0c;丰富的外设接口&#xff0c;内置超多算法&#xff0c;除此之外&#xff0c;开发板还带…

重学Java 10 面向对象

正是风雨欲来的时候&#xff0c;火却越烧越旺了 ——24.1.20 重点 1.为何使用面向对象思想编程 2.如何使用面向对象思想编程 3.何时使用面向对象思想编程 4.利用代码去描述世间万物的分类 5.在一个类中访问另外一个类中的成员 -> new对象 6.成员变量和局部变量的区别 一…

AutoRuns下载安装使用教程(图文教程)超详细

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 AutoRuns 是微软提供的一款「启动项管理」工具&#xff0c;可以检查开机自动加载的所有程…

写点啥 内核调优吧

一、命令xargs --------------- 参数替换 由于很多命令不支持管道|来传递参数&#xff0c;xargs用于产生某个命令的参数&#xff0c;xargs 可以读入 stdin 的数 据&#xff0c;并且以空格符或回车符将 stdin 的数据分隔成为参数&#xff0c;另外许多命令不能接受过多参数&am…

【论文解读】LERF:语言嵌入的辐射场(ICCV 2023 Oral)

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 论文链接&#xff1a;https://arxiv.org/abs/2303.09553 项目主页&#xff1a;https://lerf.io](https://lerf.io 图 1&#xff1a;语言嵌入辐射场 (LERF)。 LERF 将 CLIP 表示建立在密集、多尺度的 3D 场中。…

Beyond Compare 4 代码对比如何重新激活使用30天

Beyond Compare 4 代码对比如何重新激活使用30天 Beyond Compare 4 是一款强大的文件比较工具&#xff0c;但只有30天的试用期。如果想在试用期结束后继续使用该软件&#xff0c;可以通过修改注册表的方式来实现。具体步骤如下&#xff1a; 1 同时按住“Win”“R”键&#xf…

vue流程图

效果图 组件 <template><div class"processBox" v-if"list.length"><div class"childs"><div class"child" v-for"(item,index) in list" :key"item.id -child-index"><div class&q…

免费三款备受推崇的爬虫软件

在信息爆炸的时代&#xff0c;爬虫软件成为了数据采集、信息挖掘的得力工具。为了解决用户对优秀爬虫软件的需求&#xff0c;本文将专心分享三款备受推崇的爬虫软件&#xff0c;其中特别突出推荐147采集软件&#xff0c;为您开启爬虫软件的奇妙世界。 一、爬虫软件的重要性 爬…

【 Qt 快速上手】-②- Qt 环境搭建

文章目录 1. Qt 开发工具概述1.1 Qt Creator 介绍1.2 Visual Studio 介绍1.3 Eclipse 介绍 2. Qt SDK 的下载与安装2.1 Qt SDK 的下载2.2 Qt SDK 的安装2.3 验证 Qt SDK 安装是否成功2.4 Qt 环境变量配置 1. Qt 开发工具概述 Qt 开发环境需要安装三个部分&#xff1a; C编译器…

配置zabbix平台对数据库以及主从状态的监控

引言&#xff1a;明人不说暗话&#xff0c;今天分享下配置zabbix平台对数据库以及主从状态的监控 准备好zabbix监控平台&#xff08;zabbix-server端&#xff09;例10.12.153.235 db1客户端&#xff08;zabbix-agent&#xff09;例10.12.153.73 1.安装Zabbix存储库 # rpm -Uv…

内衣洗衣机哪个牌子好用?四款小型洗衣机全自动推荐

说起内衣洗衣机很多小伙伴都不陌生&#xff0c;对于很多小伙伴来说内衣洗衣机真的是一个提高幸福感的小家电&#xff0c;市面上的内衣洗衣机无论从功能和配置上都有着很大的区别&#xff0c;没有做攻略的小伙伴很容易就踩雷了&#xff0c;今天给大家分享四款内衣洗衣机&#xf…

进程调度算法

文章目录 主要内容一.进程调度算法1.各调度算法思想2.程序流程图3.源代码代码如下&#xff08;示例&#xff09;: 4.运行结果分析5.先来先服务算法 6.短作业优先算法7.高响应优先算法8.算法结果对比 总结 主要内容 一.进程调度算法 1.各调度算法思想 先来先服务算法&#xff0…

Mysql:重点且常用的操作和理论知识整理 ^_^

目录 1 基础的命令操作 2 DDL 数据库定义语言 2.1 数据库操作 2.2 数据表操作 2.2.1 创建数据表 2.2.2 修改和删除数据表 2.2.3 添加外键 3 DML 数据库操作语言 3.1 插入语句(INSERT) 3.2 修改语句(UPDATE) 3.3 删除语句 3.3.1 DELETE命令 3.3.2 TRUNCATE命令 4 …

java.sql.SQLException: Failed to fetch schema of XXX 问题

遇到问题&#xff1a;java.sql.SQLException: Failed to fetch schema of pay_record表 i.s.r.d.s.s.c.AbstractTableMetaCache : get table meta of the table pay_record error: Failed to fetch schema of pay_record 原因分析&#xff1a; springcloud项目中使用了se…

Yaklang 中的类型和变量

Yaklang 的类型其实非常简单&#xff0c;我们仅需要记住如下类型即可 string 字符串类型&#xff0c;用以快速构建一个字符串int 整数类型&#xff1a;在 64 位机中&#xff0c;int 和 int64 是一样的float 浮点类型&#xff0c;用来定义和表示浮点数byte 本质上等同于 uint8u…

docker安装marcocesarato/php-conventional-changelog报错

composer require --dev marcocesarato/php-conventional-changelog --no-update “marcocesarato/php-conventional-changelog”: “^1.17” 在小皮环境没问题&#xff0c;在dockerswoole环境下报错 "scripts": {"changelog": "conventional-chang…

采用云端SaaS服务的云HIS基层医院信息管理系统源码

目录 一、日常运维工作内容 二、科室巡查工作 三、网络安全管理工作内容 四、业务能力提升学习 云HIS系统业务 一、日常运维工作内容 1. 系统监控&#xff1a;每天早晨第一件事就是打开电脑&#xff0c;查看各个系统的运行状况。通过监控系统&#xff0c;可以实时了解到服…

大数据质量管制规范示例

大数据质量管制规范示例 一、前提概要二、相关概念三、管理原则四、治理委员五、应用管理六、查验方式七、考核比率八、扣分标准九、责任划分十、追责范围十一、其它条例十二、总结 一、前提概要 在当今大数据信息时代&#xff0c;大数据平台&#xff08;大数据平台开发规范示…

【ChatGPT】利用ChatGPT将图片转换成JSON文件

前言 我在创建自己的GPT时,通常会上传一些JSON文件作为知识库,我还制作了一些脚本工具,将PDF文件转换成JSON文件。但是在这个过程中产生一个问题,PDF文件中会有一些图表,JSON文件就不能存储和表达这些图表的内容了。那该怎么办呢?这里跟大家介绍一个方法,可以有效地将图…