2原型
3输出格式
版权声明:本文为博主原创文章,未经博主允许不得转载。
在数据查询中,有时候会遇到使用两个或两个以上字段对一组数据集合进行排序,较为合理的处理逻辑应该是先按照字段之间的优先级关系将待排序的数据集合递归地以同一字段的值(同一层)升序或降序的方式进行拆分,然后在以由上往下顺(广度优先方式)序对父节点的叶子节点按照指定规则进行排序。(注:如果底层支持传入compare方法,那么每一组字段排序组合设计一种compare算法,会更加高效)
SQL语句中可以使用order by语句对多个字段进行排序(暂不清楚其实现原理,有可能和上面提到的处理逻辑类似)。该篇文章会讨论一种新的处理手段,将所有参加排序的字段按照指定的优先级关系从低到高以字节填充(binary)的方式将内容追加到一个字节切片(支持扩容的数组)中(区分大小写),即将多字段的排序”归化为“单一字段的排序。
举例:s公司最近要统计不同年龄段中,不同薪资的员工信息,为了让数据更直观,上层要求按照员工年龄(出生日期)降序、员工月薪降序和员工姓名升序的规则进行排序统计。若以“归一化”方法进行排序,原理如下图。
由于出生日期可以以“19980408”的整型表示,月薪则已元作为计数单位(忽略小数部分),姓名以字符字节表示。无论是怎样的数据类型,都会以字节填充到“新字段”中,不过由于出生日期和月薪是以降序排序,我们需要对其值进行处理,新的出生日期=0xffffffff-老的出生日期,新的月薪=0xffff-老的月薪。其中“归一化”排序的核心过程为“填充字节序列+比较”。
所以该排序算法支持多字段且多类型的排序,无需为每一种排序组合都写一个排序算法,只需以字节(如上面的员工年龄和员工月薪可能需要对数据进行特殊处理)作为参数传入并获取一个“新字段”的字节序列,再以”新字段“构成的集合作为参数传入并获取到一个已经排好序的集合。
printk是在内核中运行的向控制台输出显示的函数,Linux内核首先在内核空间分配一个静态缓冲区,作为显示用的空间,然后调用sprintf,格式化显示字符串,最后调用tty_write向终端进行信息的显示。printk与printf的差异,是什么导致一个运行在内核态而另一个运行用户态?其实这两个函数的几乎是相同的,出现这种差异是因为tty_write函数需要使用fs指向的被显示的字符串,而fs是专门用于存放用户态段选择符的,因此,在内核态时,为了配合tty_write函数,printk会把fs修改为内核态数据段选择符ds中的值,这样才能正确指向内核的数据缓冲区,当然这个操作会先对fs进行压栈保存,调用tty_write完毕后再出栈恢复。总结说来,printk与printf的差异是由fs造成的,所以差异也是围绕对fs的处理。2原型
【原型】int printk(const char * fmt,…);【示例】与大多数展示printf的功能一样,我们也用一个helloworld的程序来演示printk的输出:编写一个内核模块:#include<linux/kernel.h>#include<linux/module.h>#if CONFIG_MODVERSIONS==1#define MODVERSIONS#include<linux/modversions.h>#endifMODULE_LICENSE("GPL");int init_module(){printk("hello.word-this is the kernel speaking\n");return 0;}void cleanup_module(){printk("Short is the life of a kernel module\n");}保存为文件hello.c编写一个Makefile:CC=gccMODCFLAGS:=-O6 -Wall -DMODULE -D__KERNEL__ -DLINUXhello.o:hello.c /usr/include/linux/version.h$(CC) $(MODCFLAGS) -c hello.cecho insmod hello.o to turn it on保存为文件Makefile执行make"hello.word-this is the kernel speaking"这样一条信息。然后我们开始:[root@localhost root]# insmod hello.o[root@localhost root]#并没有输出任何消息。why?这也是printf和printk的一个不同的地方用printk,内核会根据日志级别,可能把消息打印到当前控制台上,这个控制台通常是一个字符模式的终端、一个串口打印机或是一个并口打印机。这些消息正常输出的前提是──日志输出级别小于console_loglevel(在内核中数字越小优先级越高)。没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),其定义在linux26/kernel/printk.c中可以找到日志级别一共有8个级别,printk的日志级别定义如下(在include/linux/kernel.h中):#define KERN_EMERG 0/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/#define KERN_ALERT 1/*报告消息,表示必须立即采取措施*/#define KERN_CRIT 2/*临界条件,通常涉及严重的硬件或软件操作失败*/#define KERN_ERR 3/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/#define KERN_WARNING 4/*警告条件,对可能出现问题的情况进行警告*/#define KERN_NOTICE 5/*正常但又重要的条件,用于提醒*/#define KERN_INFO 6/*提示信息,如驱动程序启动时,打印硬件信息*/#define KERN_DEBUG 7/*调试级别的消息*/现在我们来修改hello.c程序,使printk的输出级别为最高:printk("<0>""hello.word-this is the kernel speaking\n");然后重新编译hello.o,并插入内核:[root@localhost root]# insmod hello.o[root@localhost root]#Message from syslogd@localhost at Sat Aug 15 05:32:22 2009 ...localhost kernel: hello.word-this is the kernel speakinghello,world信息出现了。其实printk始终是能输出信息的,只不过不一定是到了终端上。我们可以去/var/log/messages这个文件里面去查看。如果klogd没有运行,消息不会传递到用户空间,只能查看/proc/kmsg通过读写/proc/sys/kernel/printk文件可读取和修改控制台的日志级别。查看这个文件的方法如下:#cat /proc/sys/kernel/printk 6 4 1 7上面显示的4个数据分别对应控制台日志级别、默认的消息日志级别、最低的控制台日志级别和默认的控制台日志级别。可用下面的命令设置当前日志级别:# echo 8 > /proc/sys/kernel/printk这样所有级别<8,(0-7)的消息都可以显示在控制台上.3输出格式
printk函数可以指定输出的优先级:KERN_EMERG"<0>"/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/KERN_ALERT"<1>"/*报告消息,表示必须立即采取措施*/KERN_CRIT"<2>"/*临界条件,通常涉及严重的硬件或软件操作失败*/KERN_ERR"<3>"/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/KERN_WARNING"<4>"/*警告条件,对可能出现问题的情况进行警告*/KERN_NOTICE"<5>"/*正常但又重要的条件,用于提醒。常用于与安全相关的消息*/KERN_INFO"<6>"/*提示信息,如驱动程序启动时,打印硬件信息*/KERN_DEBUG"<7>"/*调试级别的消息*/如果变量类型是 , 使用 prink 的格式说明符 :int %d 或者 %x( 注: %d 是十进制, %x 是十六进制 )unsigned int %u 或者 %xlong %ld 或者 %lxunsigned long %lu 或者 %lxlong long %lld 或者 %llxunsigned long long %llu 或者 %llxsize_t %zu 或者 %zxssize_t %zd 或者 %zx原始指针值必须用 %p 输出。u64,即(unsigned long long),必须用 %llu 或者 %llx 输出,如:printk("%llu", (unsigned long long)u64_var);s64,即(long long),必须用 %lld 或者 %llx 输出,如 :printk("%lld", (long long)s64_var);如果 ( 变量类型 )<type> 的长度依赖一个配置选项 ( 例如: sector_t, blkcnt_t, phys_addr_t, resource_size_t) 或者 依赖相关的体系结构(例如: tcflag_t ),使用一个可能最大类型的格式说明符,并且显示转换它。如:printk("test: sector number/total blocks: %llu/%llu\n",(unsigned long long)sector, (unsigned long long)blockcount);版权声明:本文为博主原创文章,未经博主允许不得转载。
转载于:https://www.cnblogs.com/mao0504/p/4706638.html
NOTE0——何为上下文切换
每一个线程都有一个上下文。后者保存在线程的内核对象中。这个上下文反映了线程上一次执行时cpu寄存器的状态。大约每隔20ms(GetSystemTimeAdjustMent函数第二个参数的返回值),windows都会查看所有当前存在的线程内核对象,这些对象中只有一些是认为可以调度的。window在可调度的线程内核对象中选择一个,并将上次保存在线程上下文中的值载入cpu寄存器。这一操作成为上下文切换,可以通过spy++看线程属性。
说明:怎么确保某个线程在数据到达串行端口来的1MS之内开始运行。答案:不行。实时操作系统可以。但是window不是实时的。实时操作系统需要对底层的硬件有清楚的了解,从而指导硬盘控制器。键盘等的延时。
NOTE1——线程的挂起和恢复
有些线程对象的挂起技术大于0,这意味着该线程已经被挂起。不应该给他调度任何cpu时间。可以通过调用CreateProcess或CreateThread函数并传入CREATE_SUSPENDED标志来创建一个被挂起的线程。
可以通过调用ResumeThread函数。传入调用CreateThread时所返回的线程句柄来实现:
DWORD ResumeThread(Handle hThread);如果成功返回线程前一个挂起计数。否则返回0xffffffff,还可以通过SuspendThread来挂起线程DWORD SuspendThread(Handle hThread);任何线程都可以调用这个函数挂起另一个线程,线程可以将自己挂起。但是他无法自己恢复。实际开发中。应用程序在调用suspendthread时必须小心。因为试图挂起一个线程时。我们不知道线程在做什么。例如线程正在分配堆中的内存。线程将锁定堆。当其他线程要访问堆的时候。他们的执行将被中止。直到第一个线程恢复。之后又在确切知道目标线程是哪个。而且采用完备的措施避免出现因挂起线程而引起的问或死锁的时候。调用suspendthread才是安全的。
openThread这个函数将找到线程ID匹配的线程内核对象。并将内核对象的使用计数递增1,然后返回对象的句柄。有了这个句柄。就可以调用suspendthread或resumethread了
NOTE2——切换到另一个线程
SwitchToThread的函数。如果存在另一个可调度线程。那么系统会让此线程运行。调用这个函数时。系统查看是否存在正急需cpu时间的饥饿线程。如果没有立即返回。如果存在.switchtothread将调用该线程。(该优先级可能比swithtothread的主调线程低),
NOTE3——在实际上下文中谈context结构。
系统使用context结构记住线程的状态。这样线程在下一次获得cpu可以运行时。就可以在上次停止处继续。window实际上允许我们查看线程内核对象的内部。并获得当前cpu寄存器状态的集合。为此。只需要调用GetThreadContext:调用它之前应该先调用suspendthread,否则。系统可能正好获得调度此线程。这样一来。线程的上下文和所获得的信息就不一致了。一个线程实际有两个上下文。用户模式和内核模式。GetThreadContext只能返回用户模式上下文。
通过setthreadcontext来改变结构中的成员。并把新的寄存器值放回线程的内核对象中。同样如果要改变哪个线程的上下文。应该要暂停该线程。否则结果无法预料。
#include "windows.h"
#include<TLHELP32.H>
#include "stdio.h"
#include "winnt.h"
void SuspendProcess(DWORD dwProcessId,BOOL fsuspend);
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE,
PSTR pszCmdLine, int nCmdShow)
{
HANDLE snapshot;
PROCESSENTRY32 processinfo ;
processinfo.dwSize=sizeof(processinfo) ;
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(snapshot==NULL)
return FALSE;
BOOL status= Process32First(snapshot,&processinfo);
while(status)
{
if(stricmp("notepad.exe",processinfo.szExeFile)==0)
break;
status=Process32Next(snapshot,&processinfo);
}
if(status==0)
{
MessageBox(NULL,"没有找到你要挂起的进程","提示",MB_OK);
return 1;
}
CloseHandle(snapshot);
SuspendProcess(processinfo.th32ProcessID,1);
SuspendProcess(processinfo.th32ProcessID,0);
return 1;
}
void SuspendProcess(DWORD dwProcessId,BOOL fsuspend)
{
HANDLE snapshot;
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
THREADENTRY32 te={ sizeof(te)};
BOOL fOK=Thread32First(snapshot,&te);
for(;fOK;fOK=Thread32Next(snapshot,&te))
{
if(te.th32OwnerProcessID==dwProcessId)
{
typedef HANDLE (__stdcall *OPENTHREAD) (DWORD dwFlag, BOOL bUnknow, DWORD dwThreadId);
HMODULE hDll =::LoadLibrary("Kernel32.dll");
OPENTHREAD lpfnOpenThread = (OPENTHREAD)::GetProcAddress(hDll, "OpenThread");
HANDLE hThread = lpfnOpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
// HANDLE hThread = lpfnOpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
if(fsuspend==1)
{
SuspendThread(hThread);
CONTEXT context;
context.ContextFlags=CONTEXT_FULL;
GetThreadContext(hThread,&context);
context.Eip=0x00010000;
context.ContextFlags=CONTEXT_CONTROL;
SetThreadContext(hThread,&context);
}
else
ResumeThread(hThread);
// HANDLE hThread=OpenThread (THREAD_SUSPEND_RESUME,FALSE,te.th32OwnerProcessID);
}
}
CloseHandle(snapshot);
}NOTE4——优先级编程
调用createprocess中可以在fdwcreate参数中传入需要的优先级。一旦进程运行。可以通过setpriorityclass来改变自己的优先级
SetPriorityClass进行设置
SetPriorityClass
设置优先权
函数原型:
BOOL SetPriorityClass( HANDLE hProcess, DWORD dwPriorityClass);
GetPriorityClass
得到优先权
函数原型:
DWORD GetPriorityClass(
HANDLE hProcess
);dwPriorityClass:
ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
BELOW_NORMAL_PRIORITY_CLASS 0x00004000
HIGH_PRIORITY_CLASS 0x00000080IDLE_PRIORITY_CLASS 0x00000040
NORMAL_PRIORITY_CLASS 0x00000020REALTIME_PRIORITY_CLASS 0x00000100
例:
if (!CreateProcess("D:\\Program Files\\TTPlayer\\TTPlayer.exe", GetCommandLine(), NULL,
NULL, FALSE, CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
}BOOL fTemp = SetPriorityClass(pi.hProcess, HIGH_PRIORITY_CLASS);
//BOOL fTemp = SetPriorityClass(pi.hProcess, 21);
LONG lRet = GetPriorityClass(pi.hProcess);用来获取进程优先级的相应函数如下。getpriorityclass
NOTE5
SetProcessPriorityBoost允许或禁止系统提升一个进程中所有线程的优先级。
而SetThreadPriorityBoost则允许或禁止提升某个线程的优先级。有相应的Get函数来判断当前时候启用优先级提升。
SetFileInformationByHandle:Sets the file information for the specified file.BOOL WINAPI SetFileInformationByHandle(
__in HANDLE hFile,
__in FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
__in LPVOID lpFileInformation,
__in DWORD dwBufferSize
);系统在启动时将确定计算机中存在多少个cpu。应用程序可以通过调用GetsystemInfo来查询机器上cpu的数量。如果限制某些进程只在可用cpu的一个子集上运行。则可以调用SetProcessAffinityMask
The SetProcessAffinityMask function sets a processor affinity mask for the threads of the specified process.
BOOL SetProcessAffinityMask(
HANDLE hProcess,
DWORD_PTR dwProcessAffinityMask
);
//get system info
SYSTEM_INFO SystemInfo;
GetSystemInfo(&SystemInfo);
printf(" "
"dwNumberOfProcessors=%u, dwActiveProcessorMask=%u, wProcessorLevel=%u, "
"wProcessorArchitecture=%u, dwPageSize=%u ",
SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask, SystemInfo.wProcessorLevel,
SystemInfo.wProcessorArchitecture,SystemInfo.dwPageSize
);
if(SystemInfo.dwNumberOfProcessors <= 1) return;
DWORD dwMask = 0x0000;
DWORD dwtmp = 0x0001;
int nProcessorNum = 0;
for(int i = 0; i < 32; i++)
...{
if(SystemInfo.dwActiveProcessorMask & dwtmp)
...{
nProcessorNum++;
if(nProcessorNum <= 2)
...{
//如果系统中有多个处理器,则选择第二个处理器
dwMask = dwtmp;
}
else
...{
break;
}
}
dwtmp *= 2;
}//end of for
//进程与指定cpu绑定
SetProcessAffinityMask(GetCurrentProcess(), dwMask);
//线程与指定cpu绑定
//SetThreadAffinityMask(GetCurrentThread(),dwMask);
return ;
SetThreadAffinityMask是设置此线程只能在某个或某些处理器上运行;SetThreadIdealProcessor是在上述设置的范围内,指定线程优先在某个处理器上运行。
当vista在x86计算机上启动时。我们可以限制系统将所有的cpu数量。在启动过程中。系统将检查启动配置数据(BCD),BCD是一个取代老的boot.ini文本文件的数据存库,他在计算机的硬件和固件之上提供了一个抽象层。BCD的编程配置是通过wmi实现的。
版权声明:本文为博主原创文章,未经博主允许不得转载。
转载于:https://www.cnblogs.com/mao0504/p/4706775.html
1、802.1P优先级(有时也称COS优先级):
802.1p用户优先级定义在二层802.1Q 标签头中的TCI字段中。,和VLAN ID一起使用,位于高位起16-18bit字段,长度3bit,取值范围0-7,0优先级最低,7优先级最高
TPID(Tag ProtocolIdentifier标签协议标识):2字节的定值0X8100,表明这是一个加了802.1Q标签的帧。
TCI(Tag Control Information):2字节,包含了帧的控制信息
Priority:802.1P优先级,3bit,取值0-7
CFI:1bit,暂时保留未用,为0说明是规范格式,1为非规范格式,被用在令牌环/源路由FDDI介质访问方法中来指示封装帧中所带地址的比特次序信息。
VLANID:12bit,取值范围0-4095,由于0 和4095保留,实际取值范围是1-4094,每个支持802.1Q协议的交换机发送出来的数据包都会包含这个域,以指明自己属于哪一个VLAN
2、IP优先级和TOS优先级:
IP优先级定义在三层IP报文头中的TOS字段(8bit)中,占据高位的3bit,取值范围0-7,0优先级最低,7优先级最高
首先,看一下IPV4的报文格式
如上图所示,IPV4的报文头重包含一个8-bit的TOS(服务类型)优先级区域,它通常被分为precedence部分(IP优先级)-前3bit和TOS优先级(紧接着的4bit),最后一位作保留;格式如下:
起初,该字段定义如下(RFC1349):
IP优先级具体取值及含义如下:
111-Network Control 网络控制
110 -Internetwork Control 网间控制
101 -Critic 关键
100 - FlashOverride 疾速
011 -Flash 闪速
010 -Immediate快速
001 -Priority 优先
000 -Routine 普通
优先级6和7一般保留给网络控制数据使用,比如路由。
优先级5推荐给语音数据使用。
优先级4由视频会议和视频流使用。
优先级3给语音控制数据使用。
优先级1和2给数据业务使用。
优先级0为缺省标记值。
在标记数据时,既可以使用数值,也可以使用名称(英文名称)。
3、DSCP优先级:
由于对区分服务类型的多样化的要求,IP优先级的8个优先级是远远不够的,在之后的RFC文档中对TOS字段进行了重新的分配,命名为DSCP,DSCP优先级是把整个8位的前6位重新定义了一下,称为DSCP优先级,取值范围0-63,0优先级最低,63优先级最高。COS TOS DHCP通常要做映射机制。
由于DSCP和IP PRECEDENCE是共存的于是存在了一些兼容性的问题,而且DSCP的可读性比较差,比如DSCP 43(101011)我们并不知道对应着IP PRECEDENCE的什么取值,于是就把DSCP进行了进一步的分类。目前定义的DSCP总共分成了4类(64个优先级并未用完):
类选择器 Class Selector(CS) aaa 000
加速转发 Expedited Forwarding(EF) 101 110
确保转发 Assured Forwarding(AF) aaa bb0
尽力而为 Default(BE) 000 000
https://www.cnblogs.com/zandon/p/11923607.html
(4)IP precedence和DSCP的对应
DSCP |
IP/802.1P |
DSCP二进制 |
DSCP十进制 |
应用 |
丢包率 |
BE |
0 |
000 000 |
0[0x0a] |
Internet |
|
AF1 |
Green 1 |
001 010 |
10[0x0a] |
Leased Line |
L |
AF1 |
Green 1 |
001 100 |
12[0x0e] |
Leased Line |
M |
AF1 |
Green 1 |
001 110 |
14[0x0e] |
Leased Line |
H |
AF2 |
Green 2 |
010 010 |
18[0x12] |
IPTV VOD |
L |
AF2 |
Green 2 |
010 100 |
20[0x12] |
IPTV VOD |
M |
AF2 |
Green 2 |
010 110 |
22[0x12] |
IPTV VOD |
H |
AF3 |
Green 3 |
011 010 |
26[0x1a] |
IPTV Broadcast |
L |
AF3 |
Green 3 |
011 100 |
28[0x1a] |
IPTV Broadcast |
M |
AF3 |
Green 3 |
011 110 |
30[0x1a] |
IPTV Broadcast |
H |
AF4 |
Green 4 |
100 010 |
34[0x22] |
NGN/3G Singaling |
L |
AF4 |
Green 4 |
100 100 |
36[0x22] |
NGN/3G Singaling |
M |
AF4 |
Green 4 |
100 110 |
38[0x22] |
NGN/3G Singaling |
H |
EF |
5 |
101 110 |
46[0x2E] |
NGN/3G voice |
|
CS6(INC) |
6 |
110 000 |
48[0x2E] |
Protocol |
|
CS7(NC) |
7 |
111 000 |
56[0x2E] |
Protocol |
|