导航:首页 > 操作系统 > linux多线程调度

linux多线程调度

发布时间:2023-05-03 16:26:19

㈠ 浅析linux下进程的调度策略与优先级

在 Linux 中,线程是由进程来实现的,可以认为线程就是一个轻量级的进程,因此,线程调度是按照进程调度的方式来进行的。这样设计,线程调度流程可以直接复用进程调度流程,没必要再设计一个进程内的线程调度器了。

在 Linux 中,进程调度器是基于进程的调度策略与调度优先级来决定调度哪个进程运行。

调度策略主要包括:

调度优先级的范围是 0~99,数值越大,表示优先级越高。

其中,SCHED_OTHER、SCHED_IDLE、SCHED_BACH 为非实时调度策略,其调度优先级为 0。而 SCHED_FIFO、SCHED_RR 是实时调度策略,其调度优先级范围为 1~99。

实时调度策略的进程总是比非实时调度策略的进程优先级高。

在 Linux 内部实现中,调度器会为每个可能的调度优先级维护一个可运行的进程列表,以最高优先级列表头部的进程作为下一次调度的进程,所有的调度都是抢占式的,如果一个具有更高调度优先级的进程转换为可运行状态,那么当前运行的进程将被强制进入其等待的队列中。

SCHED_OTHER

该调度策略是默认的 Linux 分时调度策略,该调度策略为非实时的,其调度优先级总是为 0。

对于该调度策略类型的进程,调度器是基于动态优先级来调度的。动态优先级跟属性 nice 有关,nice 的值会随着进程的运行时间而动态改变,以确保所有具有 SCHED_OTHER 策略的进程公平地得到调度。

在 Linux 中,nice 的值范围为-20 ~ +19,默认值为 0。nice 值越大,则优先级越低,因此相对较低 nice 值的进程可以获得更多的处理器时间。

通过命令 ps -el 查看系统中的进程列表,其中 NI 列就是进程对应的 nice 值。

使用 top 命令,看到的 NI 列也是进程的 nice 值。

调整 nice 值,可以通过 shell 命令 nice ,该命令可以按照指定的 nice 值运行 cmd ,命令的帮助信息为:

重新调整已运行进程的 nice 值,可通过 renice 命令实现,命令的帮助信息为:

另外,可以执行 top 命令,输入 r ,根据提示输入进程的 pid ,再输入 nice 数值,也可以调整进程的 nice 值。

SCHED_FIFO

该调度策略为先入先出调度策略,简单概括,就是一旦进程占用了 CPU,则一直运行,直到有更高优先级的任务抢占,或者进程自己放弃占用 CPU。

SCHED_RR

该调度策略为时间片轮转调度策略,该调度策略是基于 SCHED_FIFO 策略的演进,其在每个进程上增加一个时间片限制,当时间片使用完成后,调度器将该进程置于队列的尾端,放在尾端保证了所有具有相同调度优先级的进程的调度公平。

使用 top 命令,如果 PR 列的值为 RT ,则说明该进程采用的是实时调度策略,其调度策略为 SCHED_FIFO 或者 SCHED_RR,而对于非实时调度策略的进程,该列的值为 NI + 20 。

可以通过命令 ps -eo state,uid,pid,ppid,rtprio,time,comm 来查看进程对应的实时优先级,实时优先级位于 RTPRIO 列下,如果进程对应的列显示为 - ,说明该进程不是实时进程。

chrt 命令可以用来很简单地更改进程的调度策略与调度优先级。在 Linux 下查看 chrt 命令的帮助信息:

比如,获取某个进程的调度策略,使用如下命令:

在比如,设置某个进程的调度策略为 SCHED_FIFO,调度优先级为 70,使用如下命令:

㈡ linux进程、线程及调度算法(三)

调度策略值得是大家都在ready时,并且CPU已经被调度时,决定谁来运行,谁来被调度。

两者之间有一定矛盾。
响应的优化,意味着高优先级会抢占优先级,会花时间在上下文切换,会影响吞吐。
上下文切换的时间是很短的,几微妙就能搞定。上下文切换本身对吞吐并多大影响, 重要的是,切换后引起的cpu 的 cache miss.
每次切换APP, 数据都要重新load一次。
Linux 会尽可能的在响应与吞吐之间寻找平衡。比如在编译linux的时候,会让你选择 kernal features -> Preemption model.
抢占模型会影响linux的调度算法。

所以 ARM 的架构都是big+LITTLE, 一个很猛CPU+ 多个 性能较差的 CPU, 那么可以把I/O型任务的调度 放在 LITTLE CPU上。需要计算的放在big上。

早期2.6 内核将优先级划分了 0-139 bit的优先级。数值越低,优先级越高。0-99优先级 都是 RT(即时响应)的 ,100-139都是非RT的,即normal。
调度的时候 看哪个bitmap 中的 优先级上有任务ready。可能多个任务哦。

在普通优先级线程调度中,高优先级并不代表对低优先级的绝对优势。会在不同优先级进行轮转。
100 就是比101高,101也会比102高,但100 不会堵着101。
众屌丝进程在轮转时,优先级高的:

初始设置nice值为0,linux 会探测 你是喜欢睡眠,还是干活。越喜欢睡,linux 越奖励你,优先级上升(nice值减少)。越喜欢干活,优先级下降(nice值增加)。所以一个进程在linux中,干着干着 优先级越低,睡着睡着 优先级越高。

后期linux补丁中

红黑树,数据结构, 左边节点小于右边节点
同时兼顾了 CPU/IO 和 nice。
数值代表着 进程运行到目前为止的virtual runtime 时间。

(pyhsical runtime) / weight * 1024(系数)。
优先调度 节点值(vruntime)最小的线程。权重weight 其实有nice 来控制。

一个线程一旦被调度到,则物理运行时间增加,vruntime增加,往左边走。
weight的增加,也导致vruntime减小,往右边走。
总之 CFS让线程 从左滚到右,从右滚到左。即照顾了I/O(喜欢睡,分子小) 也 照顾了 nice值低(分母高).所以 由喜欢睡,nice值又低的线程,最容易被调度到。
自动调整,无需向nice一样做出奖励惩罚动作,个人理解权重其实相当于nice

但是 此时 来一个 0-99的线程,进行RT调度,都可以瞬间秒杀你!因为人家不是普通的,是RT的!

一个多线程的进程中,每个线程的调度的策略 如 fifo rr normal, 都可以不同。每一个的优先级都可以不一样。
实验举例, 创建2个线程,同时开2个:

运行2次,创建两个进程
sudo renice -n -5(nice -5级别) -g(global), 会明显看到 一个进程的CPU占用率是另一个的 3倍。

为什么cpu都已经达到200%,为什么系统不觉得卡呢?因为,我们的线程在未设置优先级时,是normal调度模式,且是 CPU消耗型 调度级别其实不高。

利用chrt工具,可以将进程 调整为 50 从normal的调度策略 升为RT (fifo)级别的调度策略,会出现:

chrt , nice renice 的调度策略 都是以线程为单位的,以上 设置的将进程下的所有线程进行设置nice值
线程是调度单位,进程不是,进程是资源封装单位!

两个同样死循环的normal优先级线程,其中一个nice值降低,该线程的CPU 利用率就会比另一个CPU的利用率高。

㈢ 如何进行Linux下多线程的调试

方法一:PS
在ps命令中,“-T”选项可以开启线程查看。下面的命令列出了由进程号为<pid>的进程创建的所有线程。
1.$ ps -T -p <pid>

“SID”栏表示线程ID,而“CMD”栏则显示了线程名称。

方法二: Top
top命令可以实时显示各个线程情况。要在top输出中开启线程查看,请调用top命令的“-H”选项,该选项会列出所有Linux线程。在top运行时,你也可以通过按“H”键将线程查看模式切换为开或关。
1.$ top -H

要让top输出某个特定进程<pid>并检查该进程内运行的线程状况:
$ top -H -p <pid>

㈣ 浅谈linux 多线程编程和 windows 多线程编程的异同

linux下线程的实现,linux的线程编程有两个库pthread和pth,对于pthread的实现是内核方式的实现,每个线程在kernel中都有task结构与之对应,也就是说用ps命令行是可以看见多个线程,线程的调度也是由内核中的schele进行的。
再来看看Windows的多线程,Windows NT和Windows95是一个抢先型多任务、多线程操作系统。因为它使用抢先型的多任务,所以它拥有与UNIX同样平滑的处理和进程独立。多线程就更进一步。一个独立的程序默认是使用一个线程,不过它可以将自己分解为几个独立的线程来执行,例如,其中的一个线程可以发送一个文件到打印机,而另一个可以响应用户的输入。这个简单的程序设计修改可以明显减少用户等待的时间,让用户无需担心长时间的计算、重绘屏幕、文件读写等带来的不便。
多线程还可以让你从许多高端的多处理器NT机器中得到好处。例如,你购买了一个高级的RISC机器,可以使用多达10个CPU芯片,但在开始的时候你只购买了一个CPU。你写了一个简单的Mandelbrot set程序,你发现需要15秒的时间来重新绘制Mandelbrot set的画面。
那么,Windows平台的线程和类Unix平台(包括Linux)的进程的区别是什么呢?
熟悉WIN32编程的人一定知道,WIN32的进程管理方式与UNIX上有着很大区别,在UNIX里,只有进程的概念,但在WIN32里却还有一个“线程”的概念,那么UNIX和WIN32在这里究竟有着什么区别呢?
UNIX里的fork是七十年代UNIX早期的开发者经过长期在理论和实践上的艰苦探索后取得的成果,一方面,它使操作系统在进程管理上付出了最小的代价,另一方面,又为程序员提供了一个简洁明了的多进程方法。
WIN32里的进程/线程是继承自OS/2的。在WIN32里,“进程”是指一个程序,而“线程”是一个“进程”里的一个执行“线索”。从核心上讲,WIN32的多进程与UNIX并无多大的区别,在WIN32里的线程才相当于UNIX的进程,是一个实际正在执行的代码。但是,WIN32里同一个进程里各个线程之间是共享数据段的。这才是与UNIX的进程最大的不同。
对于多任务系统,共享数据区是必要的,但也是一个容易引起混乱的问题,在WIN32下,一个程序员很容易忘记线程之间的数据是共享的这一情况,一个线程修改过一个变量后,另一个线程却又修改了它,结果引起程序出问题。但在UNIX下,由于变量本来并不共享,而由程序员来显式地指定要共享的数据,使程序变得更清晰与安全。

㈤ linux如何实现多线程

#/bin/bashall_num=10a=$(date +%H%M%S)for num in `seq 1 ${all_num}`do
sleep 1
echo ${num}
done

b=$(date +%H%M%S)

echo -e "startTime:\t$a"echo -e "endTime:\t$b"

㈥ linux多线程程序怎么调试

多线程程序可能存在很多潜在的bug,如data race,dead lock,信号bug等,而这些bug一向很难调试,现在有很多论文都是基于多线程程序的调试技术的,比如model check,死锁检测,replay技术等,也有很多对应的工具,如intel的pinplay,微软的Zing等。关于这些技术和工具,如果感兴趣可以 google相应的论文进一步了解。这里我主要讲述的是我在对二进制翻译下多线程程序调试中经常使用的一些方法以及一些调试经验,虽然我的调试的是二进制翻译器,但是这些方法也同样适用于大多数多线程程序。
1、最直接的方法就是在源程序插入printf语句来打印出一些有用的变量。这种方法的优点是不用借助其他工具就可以对程序的运行进行观察,缺点是插入语句的位置、粒度等都需要调试者自己去权衡,如果插入过多的打印语句,则频繁的IO操作会使程序运行变慢,线程行为改变,有些bug甚至不会再出现。至于需要在什么地方插入语句,首先,只打印有必要的变量,一个语句可以打印多个变量;其次,在循环中,我们可以通过设置一些条件来降低打印的粒度,比如下面这段代码:
1 2 3 4 5 6 7 8 while(flag){ pc = getpc(); printf(“pc is:0x%x\n”, pc);//我们插入的打印语句 ...... ...... //do somthing using pc; }
假设我们对pc的取值很感兴趣,需要打印出所有pc取到过的值,但是大多数情况下,getpc()的返回值都同上一次的返回值相同,这样我们printf出来的就会有很多重复值。这种情况下我们可以用下面这种插桩方式来去处重复值:
1 2 3 4 5 6 7 8 9 10 11 int lastpc; //定义为全局变量或局部静态变量 while(flag){ pc = getpc(); if(pc !=lastpc){ lastpc = pc; printf(“pc is:0x%x\n”, pc); } ...... ......//do somthing using pc }
这样通过一个简单的判断就可以省掉很多没有必要的输出。很多别的情形,比如我们只关心某一变量等于特定值(比如0)时其他变量的状态,我们就没有必要把改变量不等于0时的状态打印出来。总之,能省则省,只打印我们需要的。
2、利用gdb的attach功能和sleep()函数。gdb是由gnu维护的功能强大的调试工具,并且支持多线程程序的调试,可以在gdb下直接运行一个多线程程序,通过thread等命令进行调试。但是很多多线程程序在其他工具(gdb,pin,strace等)监管下,原有的bug就不会出现。这的确是很让人头疼的事情,也是我十分不喜欢这个方法的原因,想象一下,一个程序直接跑就出错,但是放到gdb下就能得到正确的结果,好像故意在耍我们一样。我更喜欢使用gdb的attach功能,我们可以通过下面的命令来让gdb接管一个运行的线程:
1 gdb attach <pid>
这种方法的好处是能够使gdb对程序执行的影响最小,而且可以只接管程序中某一条我们所关心的线程,而其他线程不受影响。
这时有人会问,如果线程执行过快,我们还没来得及attach线程就已经执行完或者mp掉了,这种情况该怎么办?解决方法很简单,既然线程执行过快,我们就让它等一等,可以在源代码中让我们关心这个线程sleep()一小会儿,这样我们就有足够的时间来attach它,并且attach的位置我们也可以进行控制,想在哪里attach,就在哪里sleep。
3、第三种方法是利用信号处理函数来获取一些信息。在多线程程序的压力测试中,很多错误要每隔几百几千次运行才能出现一次,而这种错误的replay是很困难的,因此捕捉到这种错误的现场很重要。这里我习惯利用信号处理程序来保存这样的现场,这样你可以晚上写个脚本让程序无限跑,早上起来你会发现程序停在出错的地方,这是很惬意的事情。
多数多线程程序出错,都是访问非法内存,也就是我们常说的“段错误”(segmentation fault),程序发生非法内存的访问,系统会发给线程一个SIGSEGV信号,这个信号默认处理为core掉该线程。我们可以对这个信号进行利用,为其注册一个信号处理函数:
1 2 3 4 struct sigaction act; act.sa_flags = SA_SIGINFO; act.sa_sigaction = signal_handler; sigaction(SIGSEGV, &act, NULL); //SIGSEGV表示该信号的值
信号处理函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void signal_handler(int host_signum, siginfo_t *info, void *puc){ structucontext *uc = (struct ucontext *)puc; int loopflag = 1; while(loopflag)//可以在gdb中手动更改loopflag的值跳出循环 sleep(1); ...... //这里可以打印一些感兴趣的变量 }
函数参数中,puc是一个体系结构相关的指针,不同的体系结构,指针指向的结构不一样,里面存放了发生信号时线程的寄存器的值,程序地址等信息,函数内第一句话的目的就是把void类型转换成ucontext结构类型,这样在gdb中可以直接print出该结构的成员。
函数中sleep的作用是让程序停在信号处理程序中,以给我们足够的时间进行attach。如果想让程序继续运行下去,手动把loopflag修改为1即可。用while循环的目的是我们可以在运行时手动控制sleep的时间。
这种方法同样适用于其他信号带来的bug,比如SIGBUS等。在二进制翻译下,还可以使用这种方法对二进制翻译器信号处理进行跟踪和调试,具体使用读者可以自己去发掘。
4、利用strace得到我们关心的信息。大多数情况下我们用strace的目的是跟踪系统调用,但其实strace对多线程程序的调试有很大的帮助,使用strace打印多线程程序信息的命令如下:
1 strace -F ./test
如果我们对某些系统调用,如gettimeofday,ioctl不感兴趣,可以屏蔽掉
1 strace -F -etrace=\!gettimeofday,ioctl ./test
通过strace打印出的信息,我们可以对什么时候产生了一个子线程,那个线程在等待,哪个线程被唤醒,哪个线程收到信号,哪个线程core掉有一个综合的了解,这些信息对多线程调试会起到很大的作用。
还有很多方法比如利用core文件等,很多地方可以查到,我不做累赘的介绍。总之技术是死的,但是方法是灵活的,当传统方法解决不了一个问题的时候,可以放开思路尝试其他的方法。

㈦ Linux系统进程调度

主要参考 :Linux manual page - sched

自从linux内核2.6.23以来,默认的进高哗扮程调度器就被设置为完全公平调度器(CFS,complete fair scheler),取代了之前的O(1)调度器。

每个线程都有一个静态调度优先级,即 sched_priority 字段。

一个线程的调度策略决定了线程会被插入到同级静态优先级的线程队列的位置,以及它在队列中会怎样移动。

所有的调度都是可插入的,如果一个更高静态优先级的线程准备好了,现在运行中的线程就会被插入。而调度策略则仅仅影响了同样静态优先级的线程。

进程(线程)可以通过系芦桥统调用设置自身或者其他进程(线程)的调度策略。

其中 pid 为0时,设置自身的调度策略和参数。结构体 sched_attr 包含以下戚灶字段: size 、 sched_policy (即调度策略,具体会在下一节介绍)、 sched_flags 、 sched_nice 、 sched_runtime 、 sched_deadline 、 sched_period (最后三个为 SCHED_DEADLINE 相关的参数)。当设置成功,系统调用返回0;否则返回-1,并会设置 errno 。

普通进程: SCHED_OTHER / SCHED_BATCH / SCHED_IDLE
实时进程: SCHED_FIFO / SCHED_RR
特殊实时进程: SCHED_DEADLINE
静态优先级:Static_priority:对于普通进程,静态优先级为0;对于实时进程,静态优先级为1-99,99为最高优先级。
动态优先级:Dynamic_priority:仅对普通进程有用,取决于nice和一个动态调整的量(比如进程ready却没被调度,则增加)。

㈧ 现在的多核CPU,Linux操作系统是否能够实现单个进程(多线程)的多核调度(跨CPU核心调度)

现在的技术,还是一个线程只能运行在一个 CPU 上。多核心,必须用多线程/进程来运行才能实现最大化。当然,你可以单个线程不停的在所有的 CPU 上来回跳。但是效率会很低很低。
因为 CPU 有寄存器和缓存的问题。如果你切换 CPU 运行,所有的数据都要进行一次传递。非常浪费时钟(在 CPU 上,程序执行不是一个时钟马上就能任意执行一个指令,而是流水线作业,一个指令需要很多个时钟才能处理完,数据存取也都要等)。

这也因为程序原本就都是顺序执行的。你没办法让一个程序的后面的结果可以跳过前面的结果而得出。
当然,现在 CPU 确实有这种技术,叫做乱序执行。也就是当前面的过程还没有计算时,后面的指令先计算。但是这种事情是要靠猜测的,而且这也仅仅是分支预测,依然不能预测某个计算的结果。即便猜的再准确,也有错的时候。奔腾4 最老的版本就有这个问题,流水线太长。计算后发现错了。整条流水线需要清空重新计算。有严重性能问题的奔腾4 CPU ,流水线长度是 31 级。也就是一个程序至少 31 个时钟周期才能从推到流水线后到真正执行。直接浪费了 31 个时钟周期。

所以目前的技术来说,单线程多核新协同计算,技术上不可能实现。
提高性能,就是整理数据处理的算法,把多次重复计算的过程,拆成多条线程分别计算。从而保证 CPU 多核新的效率最大化。每个线程可以共享同一块数据,自己读取自己的数据计算使可以的。不过,这时候就有另外一个问题,数据寻址和传递的性能问题。

㈨ linux多线程

线程是进程内独立的一条运行路线,处理器调度的最小单元,也可以称为轻量级进程。线程可以对进程的内存空间和资源进行访问,并与同一进程中的其他线搏好程共享。因此,线程的上下文切换的开销比创建圆银拆进程小很多。

Pthread是一套用户级线程库,但在linux上实现时,却使用了内核级线程来完成,这样提高的线程的并发性.Pthread是由POSIX提供的橘枣一套通用的线程库,具有很好的移植性.

㈩ Linux下多线程和多进程程序的优缺点,各个适合什么样的业务场景

IBM有个家伙做了个测试,发现切换线程context的时候,windows比linux快一倍多。进出最快的锁(windows2k的 critical section和linux的pthread_mutex),windows比linux的要快五倍左右。当然这并不是说linux不好,而且在经过实际编程之后,综合来看我觉得linux更适合做high performance server,不过在多线程这个具体的领域内,linux还是稍逊windows一点。这应该是情有可原的,毕竟unix家族都是从多进程过来的,而 windows从头就是多线程的。
如果是UNIX/linux环境,采用多线程没必要。
多线程比多进程性能高?误导!
应该说,多线程比多进程成本低,但性能更低。
在UNIX环境,多进程调度开销比多线程调度开销,没有显着区别,就是说,UNIX进程调度效率是很高的。内存消耗方空数嫌面,二者只差全局数据区,现在内存都很便宜,服务器内存动辄若干G,根本不是问题。
多进程是立体交通系统,虽然造价高,上坡下坡多耗点油,但是不堵车。
多线程是平面交通系统,造价低,但红绿灯太多,老堵车。
我们现在都开跑车,油(主频)有的是,不怕上坡下坡,就怕堵车。
高性能交易服务器中间件,如TUXEDO,都是主张多进程的。实际测试表明,TUXEDO性能和并发效率是非常高的。TUXEDO是贝尔实验室的,与UNIX同宗,应该是对UNIX理解最为深刻的,他们的意见应该具有很大的参考意义。

多线程的优点:
无需跨进程边界;
程序逻辑和控制方式简单;
所有线程可以直接共享内存和变量等;
线程方式消耗的总资源比进程方式好;
多线程缺点:
每个线程与主程序共用地址空间,受限于2GB地址空间;
线程之间的同步和加锁控制比较麻烦;
一个线程的崩溃可能影响到整个程序的稳定性;
到达一定的线程数程度后,即使再增加CPU也无法提高性能,例如Windows Server 2003,大约是1500个左右的线程数就快到极限了(线程堆栈设定为1M),如果设定线程堆栈为2M,还达不到1500个线程总数;
线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的毕圆CPU

多进程优点:
每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
通过增加CPU,就可以容易扩充性能;
可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效斗手率低也没关系;
每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大
多线程缺点:
逻辑控制复杂,需要和主程序交互;
需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算
多进程调度开销比较大;
最好是多进程和多线程结合,即根据实际的需要,每个CPU开启一个子进程,这个子进程开启多线程可以为若干同类型的数据进行处理。当然你也可以利用多线程+多CPU+轮询方式来解决问题……
方法和手段是多样的,关键是自己看起来实现方便有能够满足要求,代价也合适。

阅读全文

与linux多线程调度相关的资料

热点内容
java修改ip 浏览:149
php不需要编译吗 浏览:134
特斯拉新车如何用app控制 浏览:185
文档拖到文件夹就不见了 浏览:814
标致308压缩比是多少 浏览:749
服务器和备用服务器地址 浏览:926
程序员加班跳槽 浏览:706
青年员工在工作中如何化解压力 浏览:602
包子解压神器怎么玩才爽 浏览:733
联想加密电脑怎么做系统 浏览:881
解压最近的压力 浏览:709
如何知道王牌战争新出来的服务器 浏览:591
程序员建的房子 浏览:419
navicatlinux破解版 浏览:454
找个辅警或者程序员 浏览:452
军团td预言命令 浏览:114
营指挥员下达作战命令 浏览:258
exe打开指定文件夹 浏览:265
pdf里面怎么去水印 浏览:845
appleid账号加密码 浏览:222