Linux中term.h文件的作用解析 (linux中term.h啥意思)

Term.h文件是Linux下的头文件之一,其作用是为了简化与终端交互的过程。在Linux系统中,终端被视为标准输入输出设备,而Term.h就是这一设备的API。它包含了一些必要的函数和变量,其中最常见的函数就是tputs和tgoto函数。

在使用Term.h之前,我们需要了解一些基本概念:

1.termcap

termcap是一个Unix功能,可以通过它来获取与终端相关的信息。这些信息包括:终端类型、终端特性以及如何操作终端。Term.h文件就是建立在termcap之上的。

2.ansi escape sequences

ANSI转义序列是通过终端向程序发送的特殊字符序列。这些字符序列可以用来改变终端的颜色、清除屏幕、移动光标等等。而在程序中,我们可以选择直接输出这些字符序列,或者通过Term.h文件的函数进行处理。

现在我们将Term.h文件分为以下几个部分来进行解析:

1.Terminal capabilities

Term.h文件定义了一些函数和数据结构,它们用来获取终端的不同特性。例如:

•int tgetent(char *bp, const char *name);

这个函数用于获取终端类型的详细信息,并将其存储在缓冲区bp中。例如:tgetent(bp, “xterm”);此时bp中就存储了xterm终端的特性信息。

•char *tgetstr(const char *id, char **area);

这个函数用于获取终端功能的字符串表示形式。例如:tgetstr(“cl”, &area);它返回了与终端清除屏幕相关的字符串,并将其存储在area中。

2.Operating the terminal

在对终端进行操作的过程中,Term.h文件提供了一些常用的函数。例如:

•int tputs(const char *str, int affcnt, int (*putc)(int));

tputs函数将制定字符串输出至终端。affcnt表示影响多少行,putc是一个函数指针,用于将字符写入终端中。

•char *tparm(const char *str, …);

tparm函数用于向tputs发送参数。例如:tparm(tgetstr(“cup”, &area), row, column);此时就表示移动光标到指定行和列的位置。

3.ANSI escape sequences

除了使用Term.h文件中的函数进行终端操作之外,程序还可以直接使用ANSI escape sequences。例如:

•\033c

这个序列用于清除整个屏幕。

•\033[;m

这个序列用于设置字体的颜色。例如:\033[32m表示绿色字体。

Term.h文件是Linux下用于简化与终端交互过程的头文件。它包含了一些必要的函数和变量,最常见的函数是tputs和tgoto。它需要结合termcap来解决与终端相关的问题。此外,通过ANSI escape sequences直接操作终端是完全可以实现的。

相关问题拓展阅读:

一文搞懂 , Linux内核—— 同步管理(下)

上面讲的自旋锁,信号量和互斥锁的实现,都是使用了原子操作指令。由于原子操作会 lock,当线程在多个 CPU 上争抢进入临界区的时候,都会操作那个在多个 CPU 之间共享的数据 lock。CPU 0 操作了 lock,为了数据的一致性,CPU 0 的操作如厅雀会导致其他 CPU 的 L1 中的 lock 变成 invalid,在随后的来自其他 CPU 对 lock 的访问会导致 L1 cache miss(更准确的说是communication cache miss),必须从下一个 level 的 cache 中获取。

这就会使缓存一致性变得很糟,导致性能下降。所以内核提供一种新的同步方式:RCU(读-复制-更新)。

RCU 解决了什么

RCU 是读写锁的高性能版本,它的核心理念是读者访问的同时,写者可以更新访问对象的副本,但写者需要等待所渣早有读者完成访问之后,才能删除老对象。读者没有任何同步开销,而写者的同步开销则取决于使用的写者间同步机制。

RCU 适用于需要频繁的读取数据,而相应修改数据并不多的情景,例如在文件系统中,经常需要查找定位伏迟目录,而对目录的修改相对来说并不多,这就是 RCU 发挥作用的更佳场景。

RCU 例子

RCU 常用的接口如下图所示:

为了更好的理解,在剖析 RCU 之前先看一个例子:

#include#include#include#include#include#include#include#includestructfoo{inta;structrcu_headrcu;};staticstructfoo*g_ptr;staticintmyrcu_reader_thread1(void*data)//读者线程1{structfoo*p1=NULL;while(1){if(kthread_should_stop())break;msleep(20);rcu_read_lock();mdelay(200);p1=rcu_dereference(g_ptr);if(p1)printk(“%s: read a=%d\n”,__func__,p1->a);rcu_read_unlock();}return0;}staticintmyrcu_reader_thread2(void*data)//读者线程2{structfoo*p2=NULL;while(1){if(kthread_should_stop())break;msleep(30);rcu_read_lock();mdelay(100);p2=rcu_dereference(g_ptr);if(p2)printk(“%s: read a=%d\n”,__func__,p2->a);rcu_read_unlock();}return0;}staticvoidmyrcu_del(structrcu_head*rh)//回收处理操作{structfoo*p=container_of(rh,structfoo,rcu);printk(“%s: a=%d\n”,__func__,p->a);kfree(p);}staticintmyrcu_writer_thread(void*p)//写者线程{structfoo*old;structfoo*new_ptr;intvalue=(unsignedlong)p;while(1){if(kthread_should_stop())break;msleep(250);new_ptr=kmalloc(sizeof(structfoo),GFP_KERNEL);old=g_ptr;*new_ptr=*old;new_ptr->a=value;rcu_assign_pointer(g_ptr,new_ptr);call_rcu(&old->rcu,myrcu_del);printk(“%s: write to new %d\n”,__func__,value);value++;}return0;}staticstructtask_struct*reader_thread1;staticstructtask_struct*reader_thread2;staticstructtask_struct*writer_thread;staticint__initmy_test_init(void){intvalue=5;printk(“figo: my module init\n”);g_ptr=kzalloc(sizeof(structfoo),GFP_KERNEL);reader_thread1=kthread_run(myrcu_reader_thread1,NULL,”rcu_reader1″);reader_thread2=kthread_run(myrcu_reader_thread2,NULL,”rcu_reader2″);writer_thread=kthread_run(myrcu_writer_thread,(void*)(unsignedlong)value,”rcu_writer”);return0;}staticvoid__exitmy_test_exit(void){printk(“goodbye\n”);kthread_stop(reader_thread1);kthread_stop(reader_thread2);kthread_stop(writer_thread);if(g_ptr)kfree(g_ptr);}MODULE_LICENSE(“GPL”);module_init(my_test_init);module_exit(my_test_exit);

执行结果是:

myrcu_reader_thread2:reada=0myrcu_reader_thread1:reada=0myrcu_reader_thread2:reada=0myrcu_writer_thread:writetonew5myrcu_reader_thread2:reada=5myrcu_reader_thread1:reada=5myrcu_del:a=0

RCU 原理

可以用下面一张图来总结,当写线程 myrcu_writer_thread 写完后,会更新到另外两个读线程 myrcu_reader_thread1 和 myrcu_reader_thread2。读线程像是订阅者,一旦写线程对临界区有更新,写线程就像发布者一样通知到订阅者那里,如下图所示。

写者在拷贝副本修改后进行 update 时,首先把旧的临界资源数据移除(Removal);然后把旧的数据进行回收(Reclamation)。结合 API 实现就是,首先使用 rcu_assign_pointer 来移除旧的指针指向,指向更新后的临界资源;然后使用 synchronize_rcu 或 call_rcu 来启动 Reclaimer,对旧的临界资源进行回收(其中 synchronize_rcu 表示同步等待回收,call_rcu 表示异步回收)。

为了确保没有读者正在访问要回收的临界资源,Reclaimer 需要等待所有的读者退出临界区,这个等待的时间叫做宽限期(Grace Period)。

Grace Period

中间的黄色部分代表的就是 Grace Period,中文叫做宽限期,从 Removal 到 Reclamation,中间就隔了一个宽限期,只有当宽限期结束后,才会触发回收的工作。宽限期的结束代表着 Reader 都已经退出了临界区,因此回收工作也就是安全的操作了。

宽限期是否结束,与 CPU 的执行状态检测有关,也就是检测静止状态 Quiescent Status。

Quiescent Status

Quiescent Status,用于描述 CPU 的执行状态。当某个 CPU 正在访问 RCU 保护的临界区时,认为是活动的状态,而当它离开了临界区后,则认为它是静止的状态。当所有的 CPU 都至少经历过一次 Quiescent Status 后,宽限期将结束并触发回收工作。

因为 rcu_read_lock 和 rcu_read_unlock 分别是关闭抢占和打开抢占,如下所示:

staticinlinevoid__rcu_read_lock(void){preempt_disable();}

staticinlinevoid__rcu_read_unlock(void){preempt_enable();}

所以发生抢占,就说明不在 rcu_read_lock 和 rcu_read_unlock 之间,即已经完成访问或者还未开始访问。

Linux 同步方式的总结

资料免费领

学习直通车

linux中term.h啥意思的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux中term.h啥意思,Linux中term.h文件的作用解析,一文搞懂 , Linux内核—— 同步管理(下)的信息别忘了在本站进行查找喔。


数据运维技术 » Linux中term.h文件的作用解析 (linux中term.h啥意思)