linux线程
linux多线程 pthread常用函数详解

linux多线程pthread常用函数详解Linux多线程是指在Linux操作系统中运行的多个线程。
线程是执行程序的基本单位,它独立于其他线程而存在,但共享相同的地址空间。
在Linux中,我们可以使用pthread库来实现多线程程序。
本文将详细介绍pthread库中常用的函数,包括线程的创建、退出、同步等。
一、线程创建函数1. pthread_create函数pthread_create函数用于创建一个新线程。
其原型如下:cint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg);参数说明:- thread:用于存储新线程的ID- attr:线程的属性,通常为NULL- start_routine:线程要执行的函数地址- arg:传递给线程函数的参数2. pthread_join函数pthread_join函数用于等待一个线程的结束。
其原型如下:int pthread_join(pthread_t thread, void retval);参数说明:- thread:要等待结束的线程ID- retval:用于存储线程的返回值3. pthread_detach函数pthread_detach函数用于将一个线程设置为分离状态,使其在退出时可以自动释放资源。
其原型如下:cint pthread_detach(pthread_t thread);参数说明:- thread:要设置为分离状态的线程ID二、线程退出函数1. pthread_exit函数pthread_exit函数用于退出当前线程,并返回一个值。
其原型如下:cvoid pthread_exit(void *retval);参数说明:- retval:线程的返回值2. pthread_cancel函数pthread_cancel函数用于取消一个线程的执行。
Linux下查看进程和线程

在Linux中查看线程数的三种方法1、top -H手册中说:-H : Threads toggle加上这个选项启动top,top一行显示一个线程。
否则,它一行显示一个进程。
2、ps xH手册中说:H Show threads as if they were processes这样可以查看所有存在的线程。
3、ps -mp <PID>手册中说:m Show threads after processes这样可以查看一个进程起的线程数。
查看进程1. top 命令top命令查看系统的资源状况load average表示在过去的一段时间内有多少个进程企图独占CPUzombie 进程:不是异常情况。
一个进程从创建到结束在最后那一段时间遍是僵尸。
留在内存中等待父进程取的东西便是僵尸。
任何程序都有僵尸状态,它占用一点内存资源,仅仅是表象而已不必害怕。
如果程序有问题有机会遇见,解决大批量僵尸简单有效的办法是重起。
kill是无任何效果的stop模式:与sleep进程应区别,sleep会主动放弃cpu,而stop 是被动放弃cpu ,例单步跟踪,stop(暂停)的进程是无法自己回到运行状态的。
cpu states:nice:让出百分比irq:中断处理占用idle:空间占用百分比iowait:输入输出等待(如果它很大说明外存有瓶颈,需要升级硬盘(SCSI))Mem:内存情况设计思想:把资源省下来不用便是浪费,如添加内存后free值会不变,buff值会增大。
判断物理内存够不够,看交换分区的使用状态。
交互命令:[Space]立即刷新显示[h]显示帮助屏幕[k] 杀死某进程。
你会被提示输入进程ID 以及要发送给它的信号。
一般的终止进程可以使用15信号;如果不能正常结束那就使用信号9强制结束该进程。
默认值是信号15。
在安全模式中此命令被屏蔽。
[n] 改变显示的进程数量。
你会被提示输入数量。
[u] 按用户排序。
[M] 按内存用量排序。
linux下线程绑核的方法

linux下线程绑核的方法
在Linux系统中,可以使用以下几种方法来将线程绑定到特定的CPU核心上:
1. 使用taskset命令:taskset命令可以将进程或线程绑定到指定的CPU核心上。
例如,要将线程绑定到CPU核心0上,可以使用以下命令:
taskset -c 0 <线程ID>。
这样就可以将指定线程绑定到CPU核心0上。
2. 使用pthread库,在C/C++编程中,可以使用pthread库来创建线程,并使用pthread_setaffinity_np函数将线程绑定到特定的CPU核心上。
这样可以在编程时指定线程的运行核心。
3. 使用numactl工具,如果系统中有多个NUMA节点,可以使用numactl工具来将线程绑定到特定的NUMA节点上,从而实现线程绑定到特定的CPU核心。
4. 使用sched_setaffinity系统调用,在Linux系统编程中,可以使用sched_setaffinity系统调用来设置线程的亲和性,将线程绑定到指定的CPU核心上。
以上是一些常用的方法,可以帮助在Linux系统中将线程绑定到特定的CPU核心上。
这些方法可以根据具体的需求和系统环境来选择合适的方式来实现线程绑定。
希望这些信息能够帮助你理解在Linux下线程绑核的方法。
linux线程间通信的几种方法

linux线程间通信的几种方法Linux是一种开源的操作系统,它支持多线程编程,因此线程间通信是非常重要的。
线程间通信是指在多个线程之间传递数据或信息的过程。
在Linux中,有多种方法可以实现线程间通信,本文将介绍其中的几种方法。
1. 信号量信号量是一种用于线程间同步和互斥的机制。
它可以用来控制对共享资源的访问。
在Linux中,信号量是由sem_t类型的变量表示的。
它有三个主要的操作:初始化、P操作和V操作。
初始化操作用于初始化信号量的值。
P操作用于获取信号量,如果信号量的值为0,则线程会被阻塞,直到信号量的值大于0。
V操作用于释放信号量,将信号量的值加1。
下面是一个使用信号量实现线程间通信的例子:```#include <stdio.h>#include <pthread.h>#include <semaphore.h>sem_t sem;void *thread1(void *arg){sem_wait(&sem);printf("Thread 1\n");sem_post(&sem);pthread_exit(NULL);}void *thread2(void *arg){sem_wait(&sem);printf("Thread 2\n");sem_post(&sem);pthread_exit(NULL);}int main(){pthread_t t1, t2;sem_init(&sem, 0, 1);pthread_create(&t1, NULL, thread1, NULL); pthread_create(&t2, NULL, thread2, NULL); pthread_join(t1, NULL);pthread_join(t2, NULL);sem_destroy(&sem);return 0;}```在这个例子中,我们创建了两个线程,它们都需要获取信号量才能执行。
linux线程间通信方式

linux线程间通信方式
Linux 线程间通信方式包括以下几种:
1. 管道通信:管道是一种半双工的通信方式,只能用于具有亲缘关系的进程之间的通信,父进程创建管道,在进程间传递数据。
2. 信号通信:信号是一种异步通信方式,在进程之间传递简单的信息。
一个进程向另一个进程发送一个信号,另一个进程收到信号后就可以采取相应的操作。
3. 共享内存通信:共享内存是最快的进程间通信方式,可以将内存区域映射到多个进程的地址空间中,实现进程间数据的共享。
需要注意解决信号量、锁等同步问题。
4. 信号量通信:信号量是一种计数器,用来协调多个进程对共享资源的访问。
多个进程需要对信号量进行操作,以实现对共享资源的访问控制。
5. 消息队列通信:消息队列是一种通过消息传递来进行通信的机制,可以在进程之间传递数据块,通常用于进程间的同步和异步通信。
6. 套接字通信:套接字是基于网络通信的一种进程间通信方式,可用于同一主机上进程间通信,也可以在不同主机之间通信。
套接字是基于 TCP/IP 协议栈实现的,需要在数据传输时注意网络传输和数据结构转换等问题。
以上是 Linux 线程间通信的主要方式,开发者可以根据不同的需求和场景选择合适的方式。
linux pthread 用法

linux pthread 用法Linux pthread(POSIX线程)是一种多线程库,它提供了在Linux系统上创建和管理线程的API。
使用pthread库,可以编写多线程程序,实现并发执行和资源共享。
下面是一些常用的pthread函数和用法:1.pthread_create():用于创建一个新的线程。
它接受一个指向线程属性的指针,一个指向线程函数的指针,以及传递给线程函数的参数。
函数原型为:intpthread_create(pthread_t *thread, const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg);2.pthread_join():用于等待一个线程的结束。
它接受一个指向线程标识符的指针,以及一个指向用于存储线程返回值的指针的指针。
函数原型为:intpthread_join(pthread_t thread, void **retval);3.pthread_self():用于获取当前线程的标识符。
函数原型为:pthread_tpthread_self(void);4.pthread_detach():用于将一个线程从系统中分离出去。
这通常用于在后台运行的任务,不需要手动等待它们完成。
函数原型为:int pthread_detach(pthread_t thread);5.pthread_equal():用于比较两个线程标识符是否相等。
函数原型为:intpthread_equal(pthread_t thread1, pthread_t thread2);6.pthread_mutex_init():用于初始化一个互斥锁。
函数原型为:intpthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); 7.pthread_mutex_lock():用于获取一个互斥锁。
linux 线程优先级设置方法

linux 线程优先级设置方法Linux操作系统中,线程是轻量级的进程,合理设置线程的优先级可以优化系统资源的分配,提高程序的执行效率。
本文将详细介绍Linux线程优先级的设置方法。
一、线程优先级概述在Linux操作系统中,线程优先级通常分为两种:静态优先级和动态优先级。
1.静态优先级:在创建线程时分配的优先级,通常在程序运行过程中不会改变。
2.动态优先级:系统根据线程的运行情况动态调整的优先级,通常与线程的CPU使用时间、等待时间等因素有关。
二、设置线程优先级的方法1.使用sched_setparam()函数设置静态优先级函数原型:```cint sched_setparam(pid_t pid, const struct sched_param *param);```示例代码:```c#include <stdio.h>#include <unistd.h>#include <sched.h>#include <pthread.h>void *thread_function(void *arg) {// 线程函数代码}int main() {pthread_t tid;struct sched_param param;int policy;// 创建线程pthread_create(&tid, NULL, thread_function, NULL);// 获取当前线程的调度策略和优先级pthread_getschedparam(pthread_self(), &policy, ¶m);// 设置优先级(数值越大,优先级越高)param.sched_priority = 30;// 设置线程优先级if (pthread_setschedparam(tid, policy, ¶m) != 0) { perror("pthread_setschedparam");return 1;}// 等待线程结束pthread_join(tid, NULL);return 0;}```2.使用nice()函数设置动态优先级函数原型:```cint nice(int inc);```示例代码:```c#include <stdio.h>#include <unistd.h>#include <sys/resource.h>int main() {// 获取当前进程的nice值int old_nice = nice(0);// 设置新的nice值(数值越小,优先级越高)if (nice(-10) == -1) {perror("nice");return 1;}// 输出新的优先级printf("New priority: %d", old_nice - 10);return 0;}```三、总结本文介绍了Linux线程优先级的设置方法,包括使用sched_setparam()函数设置静态优先级和使用nice()函数设置动态优先级。
linux 线程优先级原理

linux 线程优先级原理
在 Linux 系统中,线程优先级主要由计划程序(Scheduler)负责调度。
计划程序的作用是根据特定的调度算法来决定哪个线程可以被执行,以及执行的时间和顺序。
Linux 系统中的线程优先级可以分为动态优先级和静态优先级
两种。
动态优先级是在运行时根据线程的运行情况动态调整的,而静态优先级则是通过设置线程的优先级属性来确定,与运行状态无关。
linux 线程的优先级范围是 1 到 99,数字越小表示优先级越高。
默认情况下,线程的优先级是 0,也就是最低优先级。
线程的
优先级可以使用 sched_setscheduler 函数进行设置,也可以通
过 nice 命令在终端中进行设置。
在 Linux 系统中,线程的优先级决定了该线程获得 CPU 的时
间片的大小。
优先级越高的线程获得的时间片越大,执行的机会也越多。
如果一个线程持续长时间地占用 CPU,那么其他
线程就可能会得不到执行的机会,这就会导致系统的性能下降。
因此,合理设置线程的优先级是非常重要的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
关于linux线程
在许多经典的操作系统教科书中, 总是把进程定义为程序的执行实例, 它并不执行什么, 只是维护应用程序所需的各种资源. 而线程则是真正的执行实体.为了让进程完成一定的工作, 进程必须至少包含一个线程. 如图1.
进程所维护的是程序所包含的资源(静态资源), 如: 地址空间, 打开的文件句柄集, 文件系统状态, 信号处理handler, 等;
线程所维护的运行相关的资源(动态资源), 如: 运行栈, 调度相关的控制信息, 待处理的信号集, 等;
然而, 一直以来, linux内核并没有线程的概念. 每一个执行实体都是一个task_struct结构, 通常称之为进程. 如图2.
进程是一个执行单元, 维护着执行相关的动态资源. 同时, 它又引用着程序所需的静态资源.通过系统调用clone创建子进程时, 可以有选择性地让子进程共享父进程所引用的资源. 这样的子进程通常称为轻量级进程.linux上的线程就是基于轻量级进程, 由用户态的pthread库实现的.使用pthread以后, 在用户看来, 每一个task_struct就对应一个线程, 而一组线程以及它们所共同引用的一组资源就是一个进程.但是, 一组线程并不仅仅是引用同一组资源就够了, 它们还必须被视为一个整体.对此, POSIX标准提出了如下要求:
1, 查看进程列表的时候, 相关的一组task_struct应当被展现为列表中的一个节点; 2, 发送给这个"进程"的信号(对应kill系统调用), 将被对应的这一组task_struct所共享, 并且被其中的任意一个"线程"处理;
3, 发送给某个"线程"的信号(对应pthread_kill), 将只被对应的一个task_struct接收, 并且由它自己来处理;
4, 当"进程"被停止或继续时(对应SIGSTOP/SIGCONT信号), 对应的这一组task_struct 状态将改变;
5, 当"进程"收到一个致命信号(比如由于段错误收到SIGSEGV信号), 对应的这一组task_struct将全部退出;
6, 等等(以上可能不够全);
linuxthreads
在linux 2.6以前, pthread线程库对应的实现是一个名叫linuxthreads的lib.
linuxthreads利用前面提到的轻量级进程来实现线程, 但是对于POSIX提出的那些要求, linuxthreads除了第5点以外, 都没有实现(实际上是无能为力):
1, 如果运行了A程序, A程序创建了10个线程, 那么在shell下执行ps命令时将看到11个A进程, 而不是1个(注意, 也不是10个, 下面会解释);
2, 不管是kill还是pthread_kill, 信号只能被一个对应的线程所接收;
3, SIGSTOP/SIGCONT信号只对一个线程起作用;
还好linuxthreads实现了第5点, 我认为这一点是最重要的. 如果某个线程"挂"了,整个进程还在若无其事地运行着, 可能会出现很多的不一致状态. 进程将不是一个整体,而线程也不能称为线程.或许这也是为什么linuxthreads虽然与POSIX的要求差距甚远,却能够存在, 并且还被使用了好几年的原因吧~
但是,linuxthreads为了实现这个"第5点", 还是付出了很多代价, 并且创造了linuxthreads本身的一大性能瓶颈.
接下来要说说, 为什么A程序创建了10个线程, 但是ps时却会出现11个A进程了. 因为linuxthreads自动创建了一个管理线程. 上面提到的"第5点"就是靠管理线程来实现的.当程序开始运行时, 并没有管理线程存在(因为尽管程序已经链接了pthread库, 但是未必会使用多线程).
程序第一次调用pthread_create时,linuxthreads发现管理线程不存在, 于是创建这个管理线程.这个管理线程是进程中的第一个线程(主线程)的儿子.然后在pthread_create中, 会通过pipe向管理线程发送一个命令, 告诉它创建线程. 即是说, 除主线程外, 所有的线程都是由管理线程来创建的, 管理线程是它们的父亲.于是, 当任何一个子线程退出时, 管理线程将收到SIGUSER1信号(这是在通过clone创建子线程时指定的). 管理线程在对应的sig_handler中会判断子线程是否正常退出, 如果不是, 则杀死所有线程, 然后自杀.
那么, 主线程怎么办呢? 主线程是管理线程的父亲, 其退出时并不会给管理线程发信号. 于是, 在管理线程的主循环中通过getppid检查父进程的ID号, 如果ID号是1, 说明父亲已经退出, 并把自己托管给了init进程(1号进程). 这时候, 管理线程也会杀掉所有子线程, 然后自杀.
可见, 线程的创建与销毁都是通过管理线程来完成的, 于是管理线程就成了linuxthreads的一个性能瓶颈.创建与销毁需要一次进程间通信, 一次上下文切换之后才能被管理线程执行, 并且多个请求会被管理线程串行地执行.
NPTL
到了linux 2.6,glibc中有了一种新的pthread线程库--NPTL(Native POSIX Threading Library).NPTL实现了前面提到的POSIX的全部5点要求. 但是, 实际上, 与其说是NPTL实现了, 不如说是linux内核实现了.
在linux 2.6中, 内核有了线程组的概念, task_struct结构中增加了一个tgid(thread group id)字段.
如果这个task是一个"主线程", 则它的tgid等于pid, 否则tgid等于进程的pid(即主线程的pid).
在clone系统调用中, 传递CLONE_THREAD参数就可以把新进程的tgid设置为父进程的tgid(否则新进程的tgid会设为其自身的pid).
类似的XXid在task_struct中还有两个:task->signal->pgid保存进程组的打头进程的pid、task->signal->session保存会话打头进程的pid。
通过这两个id来关联进程
组和会话。
有了tgid, 内核或相关的shell程序就知道某个tast_struct是代表一个进程还是代表一个线程, 也就知道在什么时候该展现它们, 什么时候不该展现(比如在ps的时候, 线程就不要展现了).
而getpid(获取进程ID)系统调用返回的也是tast_struct中的tgid, 而tast_struct 中的pid则由gettid系统调用来返回.
在执行ps命令的时候不展现子线程,也是有一些问题的。
比如程序a.out运行时,创建了一个线程。
假设主线程的pid是10001、子线程是10002(它们的tgid都是10001)。
这时如果你kill 10002,是可以把10001和10002这两个线程一起杀死的,尽管执行ps命令的时候根本看不到10002这个进程。
如果你不知道linux线程背后的故事,肯定会觉得遇到灵异事件了。
为了应付"发送给进程的信号"和"发送给线程的信号", task_struct里面维护了两套signal_pending, 一套是线程组共享的, 一套是线程独有的.
通过kill发送的信号被放在线程组共享的signal_pending中, 可以由任意一个线程来处理; 通过pthread_kill发送的信号(pthread_kill是pthread库的接口, 对应的系统调用中tkill)被放在线程独有的signal_pending中, 只能由本线程来处理.
当线程停止/继续, 或者是收到一个致命信号时, 内核会将处理动作施加到整个线程组中.
NGPT
说到这里, 也顺便提一下NGPT(Next Generation POSIX Threads).
上面提到的两种线程库使用的都是内核级线程(每个线程都对应内核中的一个调度实体), 这种模型称为1:1模型(1个线程对应1个内核级线程);
而NGPT则打算实现M:N模型(M个线程对应N个内核级线程), 也就是说若干个线程可能是在同一个执行实体上实现的.
线程库需要在一个内核提供的执行实体上抽象出若干个执行实体, 并实现它们之间的调度. 这样被抽象出来的执行实体称为用户级线程.
大体上, 这可以通过为每个用户级线程分配一个栈, 然后通过longjmp的方式进行上下文切换. (百度一下"setjmp/longjmp", 你就知道.)
但是实际上要处理的细节问题非常之多.
目前的NGPT好像并没有实现所有预期的功能, 并且暂时也不准备去实现.
用户级线程的切换显然要比内核级线程的切换快一些, 前者可能只是一个简单的长跳转, 而后者则需要保存/装载寄存器, 进入然后退出内核态. (进程切换则还需要切换地址空间等.)
而用户级线程则不能享受多处理器, 因为多个用户级线程对应到一个内核级线程上, 一个内核级线程在同一时刻只能运行在一个处理器上.
不过, M:N的线程模型毕竟提供了这样一种手段, 可以让不需要并行执行的线程运行在一个内核级线程对应的若干个用户级线程上, 可以节省它们的切换开销.
据说一些类UNIX系统(如Solaris)已经实现了比较成熟的M:N线程模型, 其性能比起linux的线程还是有着一定的优势.。