标签 APUE 下的文章
最近在学习Linux的编程,这里在博客中记录一下学习的过程。对于线程的优先级设定,在网上也看了不少的文章,大多数都只介绍了一个线程,关键是介绍的例程,设置的线程优先级都不起作用。由于之前接触的Linux编程知识比较少,这个问题困扰了我一晚上。于是接着在网上看资料,终于能够使线程的优先级设置有效。1、相关知识介绍首先总结一下,线程优先级设置的条件:a、线程的调度策略必须为:SCHED_RR或SCHED_FIFO;b、线程的继承策略必须为:PTHREAD_EXPLICIT_SCHED对于继承策略,这里举个简单的例子:如果线程A创建了线程B,则线程B的调度策略与线程A的调度策略和线程B的继承策略有关的:如果线程B继承策略为PTHREAD_INHERIT_SCHED,则线程B的调度策略与线程A相同,线程B的优先级也与线程A相同,但是线程B不能够自己修改调度策略与优先级(个人理解,不对请指教);如果线程B继承策略为PTHREAD_EXPLICIT_SCHED,则线程B的调度策略由线程属性attr决定,可以自行设置调度策略与优先级。其中继承策略必须为PTHREAD_EXPLICIT_SCHED,否则设置线程的优先级会被忽略。2、程序示例下面是一个简单的设置优先级的程序示例,通过修改任务1与任务2的优先级高低,可以观察到打印信息中,先打印的是优先级高的任务的信息:编译运行程序,由于任务2的优先级比任务1的优先级高,因此打印信息,先打印的是任务2,截图如下:接着将任务1的优先级设置为最高的,然后编译,试试看是否符合自己的预期。注:上述的测试是在单核系统中进行的测试(虚拟机设置为单核),对于普通进程的调度,是CPU根据进程优先级算出时间片,这样并不能一定保证高优先级的进程一定先运行,只不过和优先级低的进程相比,通常优先级较高的进程获得的CPU时间片会更长而已。其实,如果要想保证一个线程运行完再运行另一个线程的话,还要使用多线程的同步技术,信号量,条件变量等方法。而不是绝对依靠优先级的高低,来保证。
pthread_barrier_xxx系列函数在<pthread.h>中定义,用于多线程的同步,它包含下列三个函数:—pthread_barrier_init();—pthread_barrier_wait();—pthread_barrier_destroy();那么pthread_barrier_xxx是用来做什么的?这三个函数又怎么配合使用呢?pthread_barrier_xxx其实只做且只能做一件事,就是充当栏杆(barrier意为栏杆)形象的说就是把先后到达的多个线程挡在同一栏杆前,直到所有线程到齐,然后撤下栏杆同时放行。1)、init函数负责指定要等待的线程个数;2)、wait()函数由每个线程主动调用,它告诉栏杆“我到起跑线前了”。wait()执行末尾栏杆会检查是否所有人都到栏杆前了,如果是,栏杆就消失所有线程继续执行下一句代码;如果不是,则所有已到wait()的线程停在该函数不动,剩下没执行到wait()的线程继续执行;3)、destroy函数释放init申请的资源。1、函数原型#include <pthread.h>int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count);int pthread_barrier_wait(pthread_barrier_t *barrier);int pthread_barrier_destroy(pthread_barrier_t *barrier);参数解释:pthread_barrier_t:是一个计数锁,对该锁的操作都包含在三个函数内部,我们不用关心也无法直接操作,只需要实例化一个对象丢给它就好。pthread_barrierattr_t:锁的属性设置,设为NULL让函数使用默认属性即可。count:你要指定的等待个数。2、使用场景这种“栏杆”机制最大的特点就是最后一个执行wait的动作最为重要,就像赛跑时的起跑枪一样,它来之前所有人都必须等着。所以实际使用中,pthread_barrier_xxx常常用来让所有线程等待“起跑枪”响起后再一起行动。比如我们可以用pthread_create()生成100个线程,每个子线程在被create出的瞬间就会自顾自的立刻进入回调函数运行。但我们可能不希望它们这样做,因为这时主进程还没准备好,和它们一起配合的其它线程还没准备好,我们希望它们在回调函数中申请完线程空间、初始化后停下来,一起等待主进程释放一个“开始”信号,然后所有线程再开始执行业务逻辑代码。为了解决上述场景问题,我们可以在init时指定n+1个等待,其中n是线程数。而在每个线程执行函数的首部调用wait()。这样100个pthread_create()结束后所有线程都停下来等待最后一个wait()函数被调用。这个wait()由主进程在它觉得合适的时候调用就好。最后这个wait()就是鸣响的起跑枪。3、程序示例下面的程序,在main函数中,pthread_barrier_init()指定2+1个等待,接着创建了2个线程,然后主进程延时6秒,之后调用pthread_barrier_wait()来让线程接着运行,程序如下:程序的运行结果如下图所示:
为了让程序拥有更好的性能,有时候需要将进程或线程绑定到特定的CPU上,这样可以减少调度的开销和保护关键进程或线程。1、绑定进程到指定的CPULinux提供一个接口,可以将进程绑定到特定的CPU:#include <sched.h>int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *set);int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *set);参数:pid:进程的id号,如果pid为0,则表示本进程cpusetsize:set的大小set:运行进程的CPU,可以通过以下函数操作set:void CPU_ZERO(cpu_set_t *set); // Clears set, so that it contains no CPUs.void CPU_SET(int cpu, cpu_set_t *set); // Add CPU cpu to set.void CPU_CLR(int cpu, cpu_set_t *set); // Remove CPU cpu from set.int CPU_ISSET(int cpu, cpu_set_t *set); // Test to see if CPU cpu is a member of set.int CPU_COUNT(cpu_set_t * mask); //Return the number of CPUs in set.进程绑定到指定CPU的演示程序如下:测试:编译程序,之后运行,我编译出的文件名为a.out,执行下列命令,得到a.out的PID:ps -elf | grep a.out,之后输入命令:top -p 进程ID,接着输入f,选择P选项(移到P处,按下空格),按ESC退出,具体过程如下:此时可以看到进程在cpu0 cpu1 cpu2 cpu3之间不停切换:2、绑定线程到指定的CPU不仅仅进程可以绑定到CPU,线程也可以。Linux提供一个接口,可以将线程绑定到特定的CPU:#include <pthread.h>int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);该接口与进程绑定到CPU的接口的使用方法基本一致。当进程绑定到特定的CPU之后,线程还是可以绑定到其他的CPU的,没有冲突。示例代码如下:测试:编译程序,之后运行,我编译出的文件名为a.out,执行下列命令,得到a.out的PID:ps -elf | grep a.out,之后输入命令:top -H -p 进程ID,接着输入f,选择P选项(移到P处,按下空格)和nTH选项,按ESC退出,具体过程如下:可以看到主线程一直保持在cpu0,一个线程在cpu1 cpu2之间切换,另一个线程一直保持在cpu3:
最近在学习Linux的应用程序开发,选的书籍当然是经典的《UNIX环境高级编程》,不过在写好第一个代码编译时却遇到了一些问题,比如报错:apue.h:没有那个文件或目录、undefined reference to 'err_quit'、undefined reference to 'err_sys',这里就给大家讲讲如何去解决它,不用谢我哦。 这里是我提供给大家的源代码文件以及所需的一些文件,请大家提前下载,链接:点此下载 ,密码:5nhq。使用gcc 1-1.c编译该代码时,报出"致命错误:apue.h:没有那个文件或目录",现在将书籍提供的apue.h放在同一目录时,再次编译,发现又报另外的错误:undefined reference to 'err_quit'undefined reference to 'err_sys'因为err_sys和err_quit是作者自己提供的函数,这里需要单独的源代码文件支持,我已经提供给大家了,大家下载即可。下面是完整的解决办法:将我提供大家的include文件夹拷贝到Linux系统中,这里我放在/home/AilsonJack/me/apue目录中:然后执行命令:vim /etc/profile,在profile文件的末尾添加如下内容,保存退出:#gcc找到头文件的路径C_INCLUDE_PATH=/usr/include/libxml2:/home/AilsonJack/me/apue/includeexport C_INCLUDE_PATH接着执行命令:source /etc/profile接下来,编译1-1.c文件:gcc 1-1.c,没有报错吧,执行./a.out /home至此已经解决了编译第一个程序所出现的问题,剩下的就好好学习吧。
- 1
本站信息
目前本站共被浏览 162786 次
目前本站已经运行 3508 天
目前本站共有 165 篇文章
目前本站共有 6 条评论信息
目前本站共有 104 个标签
目前本站共有 0 条留言信息
网站创建时间: 2015年03月01日
最近更新时间: 2023年11月26日
目前本站已经运行 3508 天
目前本站共有 165 篇文章
目前本站共有 6 条评论信息
目前本站共有 104 个标签
目前本站共有 0 条留言信息
网站创建时间: 2015年03月01日
最近更新时间: 2023年11月26日
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
最新评论
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla