当前位置: 首页 > news >正文

线程相关知识

一、线程的基本概念

  • 定义:线程是轻量级的进程,可实现多任务的并发。
  • 核心定位:进程是操作系统资源分配的最小单位。线程是操作系统任务调度的最小单位。

二、线程的创建

  • 创建主体:线程由某个进程创建。
  • 资源分配:进程创建线程时,会为其分配独立的8M栈区空间。线程和所在进程及进程中的其他线程,共用进程的堆区、数据区、文本区。

三、线程的调度

  • 线程调度呈现“宏观并行,微观串行”的特点,由操作系统负责调度。

四、线程的消亡

  • 线程退出:在_thread任务函数中使用return结束线程。调用pthread_exit(NULL)退出线程。
  • 回收线程资源空间:主要通过pthread_join(tid, NULL)实现。

五、进程和线程的区别

对比维度进程线程
核心定位操作系统资源分配的最小单位操作系统任务调度的最小单位
资源消耗开销大,每次创建需要0-4G虚拟内存空间开销较小,只需所在进程开辟8M栈区空间
效率角度由操作系统创建,创建耗时比线程大;跨进程调度比跨线程调度慢由所在进程创建;跨进程调度比跨线程调度慢
通信方面不能直接通信,需使用进程间通信机制(IPC机制)通信简单,可使用线程共享区域(如全局变量)
安全性角度安全性高,各进程空间独立安全性不如进程,一个线程异常可能影响同一进程中所有线程

六、线程的相关编程

  • 线程创建
    • 函数:pthread_create(),成功返回0,失败返回非0。
    • 参数包括保存线程ID的变量地址、线程属性对象地址(NULL为默认属性)、线程任务函数指针、传递给任务函数的参数。
    • pthread_self()可获取当前线程的ID号。

  • 线程退出
    • pthread_exit(void *retval),retval为向回收线程传递参数的地址,NULL表示不传递参数。

  • 线程回收
    • 函数:pthread_join(pthread_t thread, void **retval),功能是阻塞等待回收线程资源空间,成功返回0,失败返回-1。
    • 参数thread为要回收的线程ID,retval用于保存线程退出时传递的参数,NULL表示不接收。

  • 线程回收策略
    • 分离属性的线程:不需要回收,由操作系统回收(适用于无空闲线程帮忙回收时)。
    • 非分离属性的线程:通过pthread_join()阻塞回收。
  • 线程属性
    • 分离属性:不需要被其他线程回收,会被操作系统回收,可通过pthread_detach(pthread_t thread)设置。
    • 非分离属性:可被其他线程回收或结束,为默认属性。

七、线程间通信与互斥机制

  • 线程间通信:可通过全局变量等线程共享区域进行通信。
  • 线程间互斥机制
    • 临界资源:多个线程可同时访问的资源,如全局变量、共享内存区域等,访问时存在资源竞争问题。
    • 解决资源竞争的方法:采用互斥机制,即多个线程访问临界资源时具有排他性,一次只允许一个线程访问,通过互斥锁实现。
    • 互斥锁实现步骤:
      • 创建互斥锁:pthread_mutex_t。
      • 初始化互斥锁:pthread_mutex_init(),参数包括锁对象地址和锁的属性(NULL为默认属性),成功返回0,失败返回-1。
      • 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex)。
      • 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex)。
      • 销毁锁:int pthread_mutex_destroy(pthread_mutex_t *mutex)。

代码训练:

线程创建

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>//次线程
void *task(void *arg)
{printf("I am thread : tid = %ld\n", pthread_self());
}int main(int argc, const char *argv[])
{//主进程、主线程pthread_t tid;int ret = pthread_create(&tid, NULL, task, NULL);if (ret !=0){printf("pthread_create error\n");return -1;}while (1){}return 0;
}

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>//次线程
void *task(void *arg)
{int i = 0;while (1){if (++i == 10){char str[] = {"thread over!"};//	return "hello";pthread_exit(NULL); // return NULL;}printf("I am thread : tid = %ld\n", pthread_self());sleep(1);}printf("hello world\n");return NULL;
}int main(int argc, const char *argv[])
{//主进程、主线程pthread_t tid;int ret = pthread_create(&tid, NULL, task, NULL);if (ret !=0){printf("pthread_create error\n");return -1;}//void *retval;pthread_join(tid, NULL);//printf("retval -> %s\n", (char *)retval);return 0;
}

#include <stdio.h>
#include <pthread.h>int num_g = 100;void *task1(void *arg)
{num_g = 1000;while (1){printf("th1 -> num = %d\n", num_g);sleep(1);}
}void *task2(void *arg)
{while (1){printf("th2 -> num = %d\n", num_g);sleep(1);}
}int main(int argc, const char *argv[])
{pthread_t tid[2];pthread_create(&tid[0], NULL, task1, NULL);pthread_create(&tid[1], NULL, task2, NULL);pthread_join(tid[0], NULL);pthread_join(tid[1], NULL);return 0;
}

detach.c

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>//次线程
void *task(void *arg)
{
//	printf("I am thread : tid = %ld\n", pthread_self());
}int main(int argc, const char *argv[])
{//主进程、主线程pthread_t tid;int i = 0;	while (1){int ret = pthread_create(&tid, NULL, task, NULL);if (ret !=0){printf("pthread_create error\n");return -1;}pthread_detach(tid);i++;printf("i = %d\n", i);}return 0;
}

#include <stdio.h>
#include <pthread.h>int num_g = 0;
pthread_mutex_t mutex;void *task1(void *arg)
{for (int i = 0; i < 100000; i++){pthread_mutex_lock(&mutex);num_g = num_g+1;printf("num_g = %d\n", num_g);pthread_mutex_unlock(&mutex);}
}void *task2(void *arg)
{for (int i = 0; i < 100000; i++){pthread_mutex_lock(&mutex);num_g = num_g+1;printf("num_g = %d\n", num_g);pthread_mutex_unlock(&mutex);}}int main(int argc, const char *argv[])
{pthread_t tid[2];pthread_mutex_init(&mutex, NULL);pthread_create(&tid[0], NULL, task1, NULL);pthread_create(&tid[1], NULL, task2, NULL);pthread_join(tid[0], NULL);pthread_join(tid[1], NULL);pthread_mutex_destroy(&mutex);return 0;
}

补充:

函数指针:
1. 定义:
返回值类型 (*指针名称)(形参表);
void *(*pfun)(void *);

2. 函数指针初始化
返回值类型 (*指针名称)(形参表)=函数的入口地址;

    void *(*pfun)(void *) = main_ctl;

3. 函数指针赋值:
函数指针名称=函数的入口地址;
void *(*pfun)(void *) = NULL;
pfun = main_ctl;

4. 函数指针怎么使用
函数名(实参表);
函数指针(实参表);

5. 函数指针的数组:保存多个函数指针

返回值类型 (*数组名称[n])(形参表);
void *(*pfun[5])(void *);

http://www.dtcms.com/a/336550.html

相关文章:

  • NokoPrint:安卓平台上的便捷无线打印解决方案
  • 存储引擎 InnoDB
  • 【Python】Python 面向对象编程详解​
  • k8s-单主机Master集群部署+单个pod部署lnmp论坛服务(小白的“升级打怪”成长之路)
  • 集成电路学习:什么是SIFT尺度不变特征变换
  • oom 文件怎么导到visualvm分析家
  • 双指针和codetop2(最短路问题BFS)
  • 闭区间是否存在一个开区间包含之
  • ESP32S3在圆形240x240 1.8寸GC9A01 SPI显示屏显示双眼睛表情
  • 寻找数组的中心索引
  • ai测试(六)
  • [Java恶补day50] 174. 地下城游戏
  • 数据结构03(Java)--(递归行为和递归行为时间复杂度估算,master公式)
  • 数学建模 13 SVM 支持向量机
  • 原子操作及基于原子操作的shared_ptr实现
  • PYTHON让繁琐的工作自动化-PYTHON基础
  • 【撸靶笔记】第五关:GET - Double Injection - Single Quotes - String
  • 基于STM32单片机智能RFID刷卡汽车位锁桩设计
  • Qt同步处理业务并禁用按钮
  • linux系统------kubenetes单机部署
  • LeetCode 分类刷题:2962. 统计最大元素出现至少 K 次的子数组
  • 5G虚拟仿真平台
  • [激光原理与应用-292]:理论 - 波动光学 - 驻波的本质是两列反向传播的相干波通过干涉形成的能量局域化分布
  • 安全多方计算(MPC)简述
  • Compose笔记(四十六)--Popup
  • Houdini 粒子学习笔记
  • 服装外贸管理软件 全流程优化解决方案
  • 学习记录(二十)-Overleaf如何插入参考文献
  • Chrome 插件开发实战:从入门到上架的全流程指南
  • 最长回文子串问题:Go语言实现及复杂度分析