首页 > 系统相关 >Linux 多线程基础

Linux 多线程基础

时间:2023-08-27 15:32:50浏览次数:39  
标签:int void Linux 基础 线程 pthread 进程 exit 多线程

@TOC

前言


一、多线程基础函数

1. pthread_create

创建新的线程。

#include <pthread.h>
	
	int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
	                   void *(*start_routine) (void *), void *arg);

参数说明:

  • thread: 用于存储新线程的ID。
  • attr: 线程属性,通常使用NULL表示默认属性。
  • start_routine: 线程的入口函数,线程将从该函数开始执行。
  • arg: 传递给线程入口函数的参数。

pthread_t 的具体实现可能因不同的操作系统而有所变化,但在 Linux 中,它通常是一个整数类型(例如 unsigned long int 或 unsigned int

2. pthread_self

函数返回当前线程的线程标识符(pthread_t 类型)。

pthread_t pthread_self(void);

线程标识符 tid ,用于在其他线程或线程管理函数中标识当前线程。


3. pthread_exit

用于终止当前单一线程的执行并返回一个指定的退出状态。

void pthread_exit(void *retval);

函数参数:

  • retval:指向线程的退出状态的指针。可以是指向任何类型的指针,表示线程退出时传递的信息。

通过 pthread_exit,线程可以返回一个指定的退出状态,以便创建者线程或进程可以通过 pthread_join 等函数获取该状态

注意在多线程环境中,不使用 exit 函数,取而代之使用 pthread_exit 函数,将单个线程退出。 因为 在 任何线程里 exit 会导致进程退出,这样会使其他线程为工作就结束。主线程退出不能使用 return 或 exit。


4. pthread_join

用于阻塞等待指定的线程终止,并获取该线程的退出状态。 它允许一个线程等待另一个线程的完成,以便协调线程的执行顺序和获取线程的返回结果。

int pthread_join(pthread_t thread, void **retval);

函数参数:

  • thread:要等待的线程的线程标识符(pthread_t 类型)。
  • retval:一个指针的指针,用于存储被等待线程的退出状态。

函数说明: (1). pthread_join 函数阻塞当前线程,直到指定的线程终止。 (2). 当所等待的线程终止后,调用 pthread_join 的线程将被唤醒并继续执行。 (3). pthread_join 函数返回后,调用线程可以通过 retval 参数获取被等待线程的退出状态。 (4). 被等待的线程在终止时必须使用 pthread_exit 函数返回一个退出状态,以便被等待线程能够获取到退出状态。

示例代码

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

void* my_pthread (void *arg)
{
	int *val = (int*)arg;
	printf("*val = %d\n",*val);

	sleep(2);
	printf("pid = %d, tid = %ld\n", getpid(),pthread_self());	// 获取线程id

	pthread_exit((void*)val);   // 结束线程,并返回退出状态
}

int main(void)
{
	pthread_t tid;
	int ret;
	int val = 10;
	int *threaf_status;
	
	printf("main : pid = %d\n", getpid());

	ret = pthread_create(&tid,NULL, my_pthread, (void*)&val);	// 创建线程
	if(ret != 0)
	{
		printf("pthread_create err\n");
	}

	pthread_join(tid, (void **)&threaf_status);	// 阻塞等待回收线程的状态
	printf("status : %d\n", *threaf_status);

	pthread_exit(NULL);
}

5. pthread_cancel

用于向指定线程发送取消请求,请求线程终止执行。

int pthread_cancel(pthread_t thread);

取消点 (Cancellation Point):

取消点是一个线程能够响应取消请求的特定函数调用点。 标准的 POSIX 函数(例如 sleep、read、write 等)都是取消点,线程在这些函数调用时能够接收取消请求。 线程也可以使用 pthread_testcancel 函数主动检查取消请求,并在适当的地方终止自己的执行。

6. pthread_detach

用于将一个已经创建但还未被其他线程回收的线程标记为可分离状态,以便操作系统在线程终止时自动回收线程资源。

int pthread_detach(pthread_t thread);

在线程创建之后,但在其他线程调用 pthread_join 之前,可以调用 pthread_detach 来将线程设为分离状态。

可分离状态的线程可以在终止时自动释放系统资源,无需其他线程显式回收资源。这样可以避免对线程进行 pthread_join 调用等待线程结束。

二、线程间的共享数据

线程默认共享数据段,代码段等地址空间,常用的是全局变量。 线程共享 全局变量,静态变量, 文件描述符,动态分配的堆内存,数据结构

对于共享资源的访问需要考虑线程安全性,使用适当的同步机制(如互斥锁、条件变量、读写锁等)来避免数据竞争和不一致性的问题。

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

int num = 20;

void* my_pthread (void *arg)
{
	num = 322;
printf("2 : num = %d\n", num);
	pthread_exit(NULL);   // 结束线程
}

int main(void)
{
	pthread_t tid;
	int ret;
	printf("1 : num = %d\n", num);

	ret = pthread_create(&tid,NULL, my_pthread, NULL);	// 创建线程
	if(ret != 0)
	{
		printf("pthread_create err\n");
	}

	sleep(1);
	printf("3 : num = %d\n", num);

	pthread_exit(NULL);
}

Linux 多线程基础_地址空间

三、多线程 ,进程对比

多线程

进程

pthread_create()

fork()

pthread_self()

getpid()

pthread_exit()

exit()

pthread_join()

wait() / waitpid()

pthread_cancel()

kill()

多线程和进程是并发编程中的两个重要概念,它们有着不同的特点和应用场景。下面是它们之间的比较:

  1. 进程(Process):是操作系统中的一个执行单位,具有独立的内存空间、代码和数据,可以拥有多个线程。 线程(Thread):是进程中的一个执行流程,共享进程的内存空间和资源,每个线程有自己的栈空间,但代码和数据是共享的。 资源占用:
  2. 进程:每个进程都有独立的地址空间和系统资源,包括内存、文件描述符、CPU等。创建和销毁进程的开销较大。 线程:线程共享进程的地址空间和系统资源,包括内存、文件描述符等。创建和销毁线程的开销相对较小。 切换开销:
  3. 进程:进程切换的开销较大,需要保存和恢复整个进程的上下文。 线程:线程切换的开销较小,因为线程共享进程的地址空间和资源,只需要保存和恢复线程的上下文。 通信方式:
  4. 进程:不同进程之间的通信需要使用进程间通信(IPC)机制,如管道、消息队列、共享内存等。 线程:线程之间可以通过共享内存、全局变量等直接进行通信,不需要额外的通信机制。 可靠性:
  5. 进程:由于进程拥有独立的地址空间,一个进程的崩溃不会影响其他进程。 线程:由于线程共享进程的地址空间,一个线程的崩溃可能会导致整个进程的崩溃。

总结

标签:int,void,Linux,基础,线程,pthread,进程,exit,多线程
From: https://blog.51cto.com/u_16159289/7253284

相关文章

  • Linux 提权
    普通用户提权[test@ahu~]$whoamitest//登陆到普通用户,发现创建不了其他用户[test@ahu~]$useraddaaa-bash:/usr/sbin/useradd:Permissiondenied进行身份变换[test@ahu~]$mkdir/tmp/exploit[test@ahu~]$ln/bin/ping/tmp/exploit/target[test@ahuexploit]......
  • 多线程基础
    进程在计算机中,我们把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程。某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,我们把子任务称为线程。进程和线程的关系:一个进程可以包含一个或多个线程,但至少会有一个......
  • 零基础学会用Airtest-Selenium对Firefox进行自动化测试
    1.前言本文将详细介绍如何使用AirtestIDE驱动Firefox测试,以及脱离AirtestIDE怎么驱动Firefox(VScode为例)。看完本文零基础小白也能学会Firefox浏览器自动化测试!!!2.如何使用AirtestIDE驱动Firefox浏览器对于Web自动化测试,目前AirtestIDE支持chrome浏览器和Firefox2种浏览器,关于......
  • redis 基础
    随着互联网+大数据时代的来临,传统的关系型数据库已经不能满足中大型网站日益增长的访问量和数据量。这个时候就需要一种能够快速存取数据的组件来缓解数据库服务I/O的压力,来解决系统性能上的瓶颈与其他内存型数据库相比,Redis具有以下特点:Redis不仅可以将数据完全保存在内存......
  • 图论基础
    图论基础树和图的存储无向图:没方向建图需要在两个节点间建两条相反的边add(a,b),add(b,a);有向图:有方向领接矩阵:g[a,b]=权重$a\tob$邻接表(常用):每个点上都有一个单链表,存储该点能到哪些点上去若有权重则加个w[N]数组,以idx为下标记录权值12,324,53NULL......
  • Linux权限chmod
    在Linux中,我们具有3种类型的文件权限:读(r),写(w)和执行(x)权限。这些权限确定哪些用户可以读取,写入或执行文件。您可以使用文本或八进制(数字)表示法来分配这些权限,我们将在本教程后面讨论。文件和目录可以属于文件(u),组(g)或其他(o)的所有者u-所有人的权限g-所有组的权限o-其他......
  • Linux下安装Redis
    Linux安装Redis首先,在官网上下载安装包接着使用xftp上传安装包到home目录接着解压缩安装包到opt目录使用tar-zxvfredis-5.0.14(2).tar.gz命令解压解压完成接着我们安装C++的编译器yuminstallgcc-c++安装完成检查版本gcc-v接着执行make命令make执行完成之......
  • 基础知识
    基础知识redis默认有16个数据库,这个可以在配置文件当中得到验证 而默认使用的是第0个数据库,可以使用select来进行切换数据库,切换成功之后会在端口号后面显示一个2 可以使用dbsize来查看数据库中数据的大小 还可以删除数据库中的数据,有两个命令flushall #删除全部......
  • debian系Linux中文系统目录改为英文目录的解决方法
    debian系Linux中文系统目录改为英文目录的解决方法 之前给笔记本装的kali是英文版,系统安装好了后再修改系统语言为中文,或者直接就用英文系统,也是可以的。后来笔记本的硬盘坏掉了,换ssd,然后安装kali的中文版,中文是方便,但是进去后就不爽了。打开终端:➜kerker>ls-lh总用......
  • linux下vim命令详解
    高级一些的编辑器,都会包含宏功能,vim当然不能缺少了,在vim中使用宏是非常方便的::qx    开始记录宏,并将结果存入寄存器xq    退出记录模式@x    播放记录在x寄存器中的宏命令稍微解释一下,当在normal模式下输入:qx后,你对文本的所有编辑动作将会被记录下来,再次输入q即退......