Linux内核中红黑树算法的实现详解

一、简介

平衡二叉树(BalancedBinary Tree或Height-Balanced Tree)

又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子BF(BalanceFactor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1、0和1。(此段定义来自严蔚敏的《数据结构(C语言版)》)

红黑树

R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

红黑树是一种在插入或删除结点时都需要维持平衡的二叉查找树,并且每个结点都具有颜色属性:

(1)、一个结点要么是红色的,要么是黑色的。

(2)、根结点是黑色的。

(3)、如果一个结点是红色的,那么它的子结点必须是黑色的,也就是说在沿着从根结点出发的任何路径上都不会出现两个连续的红色结点。

(4)、从一个结点到一个NULL指针的每条路径上必须包含相同数目的黑色结点。

Linux内核红黑树的算法都定义在linux-2.6.38.8/include/linux/rbtree.hlinux-2.6.38.8/lib/rbtree.c两个文件中。

二、结构体

struct rb_node
{
  unsigned long rb_parent_color;
#define RB_RED   0
#define RB_BLACK  1
  struct rb_node *rb_right;
  struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long)))); 

这里的巧妙之处是使用成员rb_parent_color同时存储两种数据,一是其双亲结点的地址,另一是此结点的着色。  __attribute__((aligned(sizeof(long))))属性保证了红黑树中的每个结点的首地址都是32位对齐的(在32位机上),也就是说每个结点首地址的bit[1]bit[0]都是0,因此就可以使用bit[0]来存储结点的颜色属性而不干扰到其双亲结点首地址的存储。

操作rb_parent_color的函数:

#define rb_parent(r)  ((struct rb_node *)((r)->rb_parent_color & ~3)) //获得其双亲结点的首地址
#define rb_color(r)  ((r)->rb_parent_color & 1) //获得颜色属性
#define rb_is_red(r)  (!rb_color(r))  //判断颜色属性是否为红
#define rb_is_black(r) rb_color(r) //判断颜色属性是否为黑
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) //设置红色属性
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) //设置黑色属性 

static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) //设置其双亲结点首地址的函数
{
  rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color) //设置结点颜色属性的函数
{
  rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
} 

初始化新结点:

static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
        struct rb_node ** rb_link)
{
  node->rb_parent_color = (unsigned long )parent;  //设置其双亲结点的首地址(根结点的双亲结点为NULL),且颜色属性设为黑色
  node->rb_left = node->rb_right = NULL;  //初始化新结点的左右子树 

  *rb_link = node; //指向新结点
} 

指向红黑树根结点的指针:

struct rb_root
{
  struct rb_node *rb_node;
}; 

#define RB_ROOT (struct rb_root) { NULL, } //初始化指向红黑树根结点的指针
#define rb_entry(ptr, type, member) container_of(ptr, type, member) //用来获得包含struct rb_node的结构体的首地址 

#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) //判断树是否为空
#define RB_EMPTY_NODE(node) (rb_parent(node) == node) //判断node的双亲结点是否为自身
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) //设置双亲结点为自身 

三、插入

首先像二叉查找树一样插入一个新结点,然后根据情况作出相应的调整,以使其满足红黑树的颜色属性(其实质是维持红黑树的平衡)。

函数rb_insert_color使用while循环不断地判断双亲结点是否存在,且颜色属性为红色。

若判断条件为真,则分成两部分执行后续的操作:

(1)、当双亲结点是祖父结点左子树的根时,则:

a、存在叔父结点,且颜色属性为红色。

b、当node是其双亲结点右子树的根时,则左旋,然后执行第c步。

c、当node是其双亲结点左子树的根时。

(2)、当双亲结点是祖父结点右子树的根时的操作与第(1)步大致相同,这里略过不谈。

若为假,则始终设置根结点的颜色属性为黑色。

void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
  struct rb_node *parent, *gparent; 

  while ((parent = rb_parent(node)) && rb_is_red(parent)) //双亲结点不为NULL,且颜色属性为红色
  {
    gparent = rb_parent(parent); //获得祖父结点 

    if (parent == gparent->rb_left) //双亲结点是祖父结点左子树的根
    {
      {
        register struct rb_node *uncle = gparent->rb_right; //获得叔父结点
        if (uncle && rb_is_red(uncle)) //叔父结点存在,且颜色属性为红色
        {
          rb_set_black(uncle); //设置叔父结点为黑色
          rb_set_black(parent); //设置双亲结点为黑色
          rb_set_red(gparent); //设置祖父结点为红色
          node = gparent; //node指向祖父结点
          continue; //继续下一个while循环
        }
      } 

      if (parent->rb_right == node) //当node是其双亲结点右子树的根时
      {
        register struct rb_node *tmp;
        __rb_rotate_left(parent, root); //左旋
        tmp = parent; //调整parent和node指针的指向
        parent = node;
        node = tmp;
      } 

      rb_set_black(parent); //设置双亲结点为黑色
      rb_set_red(gparent); //设置祖父结点为红色
      __rb_rotate_right(gparent, root); //右旋
    } else { // !(parent == gparent->rb_left)
      {
        register struct rb_node *uncle = gparent->rb_left;
        if (uncle && rb_is_red(uncle))
        {
          rb_set_black(uncle);
          rb_set_black(parent);
          rb_set_red(gparent);
          node = gparent;
          continue;
        }
      } 

      if (parent->rb_left == node)
      {
        register struct rb_node *tmp;
        __rb_rotate_right(parent, root);
        tmp = parent;
        parent = node;
        node = tmp;
      } 

      rb_set_black(parent);
      rb_set_red(gparent);
      __rb_rotate_left(gparent, root);
    } //end if (parent == gparent->rb_left)
  } //end while ((parent = rb_parent(node)) && rb_is_red(parent)) 

  rb_set_black(root->rb_node);
} 

四、删除

像二叉查找树的删除操作一样,首先需要找到所需删除的结点,然后根据该结点左右子树的有无分为三种情形:

node结点的颜色属性为黑色,则需要调用__rb_erase_color函数来进行调整。

void rb_erase(struct rb_node *node, struct rb_root *root)
{
  struct rb_node *child, *parent;
  int color; 

  if (!node->rb_left) //删除结点无左子树
    child = node->rb_right;
  else if (!node->rb_right) //删除结点无右子树
    child = node->rb_left;
  else //左右子树都有
  {
    struct rb_node *old = node, *left; 

    node = node->rb_right;
    while ((left = node->rb_left) != NULL)
      node = left; 

    if (rb_parent(old)) {
      if (rb_parent(old)->rb_left == old)
        rb_parent(old)->rb_left = node;
      else
        rb_parent(old)->rb_right = node;
    } else
      root->rb_node = node; 

    child = node->rb_right;
    parent = rb_parent(node);
    color = rb_color(node); 

    if (parent == old) {
      parent = node;
    } else {
      if (child)
        rb_set_parent(child, parent);
      parent->rb_left = child; 

      node->rb_right = old->rb_right;
      rb_set_parent(old->rb_right, node);
    } 

    node->rb_parent_color = old->rb_parent_color;
    node->rb_left = old->rb_left;
    rb_set_parent(old->rb_left, node); 

    goto color;
  } //end else 

  parent = rb_parent(node); //获得删除结点的双亲结点
  color = rb_color(node); //获取删除结点的颜色属性 

  if (child)
    rb_set_parent(child, parent);
  if (parent)
  {
    if (parent->rb_left == node)
      parent->rb_left = child;
    else
      parent->rb_right = child;
  }
  else
    root->rb_node = child; 

 color:
  if (color == RB_BLACK) //如果删除结点的颜色属性为黑色,则需调用__rb_erase_color函数来进行调整
    __rb_erase_color(child, parent, root);
} 

五、遍历

rb_firstrb_next函数可组成中序遍历,即以升序遍历红黑树中的所有结点。

struct rb_node *rb_first(const struct rb_root *root)
{
  struct rb_node *n; 

  n = root->rb_node;
  if (!n)
    return NULL;
  while (n->rb_left)
    n = n->rb_left;
  return n;
} 

struct rb_node *rb_next(const struct rb_node *node)
{
  struct rb_node *parent; 

  if (rb_parent(node) == node)
    return NULL; 

  /* If we have a right-hand child, go down and then left as far
    as we can. */
  if (node->rb_right) {
    node = node->rb_right;
    while (node->rb_left)
      node=node->rb_left;
    return (struct rb_node *)node;
  } 

  /* No right-hand children. Everything down and left is
    smaller than us, so any 'next' node must be in the general
    direction of our parent. Go up the tree; any time the
    ancestor is a right-hand child of its parent, keep going
    up. First time it's a left-hand child of its parent, said
    parent is our 'next' node. */
  while ((parent = rb_parent(node)) && node == parent->rb_right)
    node = parent; 

  return parent;
} 

六、在应用程序中使用

Linux内核中红黑树算法的实现非常通用、巧妙,而且免费又开源,因此完全可以把它运用到自己的应用程序中。

(1)、从内核中拷贝源文件:

$ mkdir redblack
$ cd redblack/
$ cp ../linux-2.6.38.8/lib/rbtree.c .
$ cp ../linux-2.6.38.8/include/linux/rbtree.h . 

(2)、修改源文件:

a、C文件rbtree.c

修改包含头文件的代码

//删除以下两行代码
#include <linux/rbtree.h>
#include <linux/module.h>
//新增以下代码,即包含当前目录中的头文件rbtree.h
#include "rbtree.h" 

删除所有的EXPORT_SYMBOL宏

EXPORT_SYMBOL(rb_insert_color);
EXPORT_SYMBOL(rb_erase);
EXPORT_SYMBOL(rb_augment_insert);
EXPORT_SYMBOL(rb_augment_erase_begin);
EXPORT_SYMBOL(rb_augment_erase_end);
EXPORT_SYMBOL(rb_first);
EXPORT_SYMBOL(rb_last);
EXPORT_SYMBOL(rb_next);
EXPORT_SYMBOL(rb_prev);
EXPORT_SYMBOL(rb_replace_node); 

b、头文件rbtree.h

删除包含头文件的代码,并添加三个宏定义

//删除以下两行代码
#include <linux/kernel.h>
#include <linux/stddef.h> 

/* linux-2.6.38.8/include/linux/stddef.h */
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif 

/* linux-2.6.38.8/include/linux/stddef.h */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 

/* linux-2.6.38.8/include/linux/kernel.h */
#define container_of(ptr, type, member) ({     \
  const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  (type *)( (char *)__mptr - offsetof(type,member) );}) 

(3)、示例代码

Linux内核红黑树的使用方法请参考linux-2.6.38.8/Documentation/rbtree.txt文件。

/* test.c */
#include <stdio.h>
#include <stdlib.h>
#include "rbtree.h" 

struct mytype {
  struct rb_node my_node;
  int num;
}; 

struct mytype *my_search(struct rb_root *root, int num)
{
  struct rb_node *node = root->rb_node; 

  while (node) {
  struct mytype *data = container_of(node, struct mytype, my_node); 

  if (num < data->num)
    node = node->rb_left;
  else if (num > data->num)
    node = node->rb_right;
  else
    return data;
  } 

  return NULL;
} 

int my_insert(struct rb_root *root, struct mytype *data)
{
  struct rb_node **tmp = &(root->rb_node), *parent = NULL; 

  /* Figure out where to put new node */
  while (*tmp) {
  struct mytype *this = container_of(*tmp, struct mytype, my_node); 

  parent = *tmp;
  if (data->num < this->num)
    tmp = &((*tmp)->rb_left);
  else if (data->num > this->num)
    tmp = &((*tmp)->rb_right);
  else
    return -1;
  } 

  /* Add new node and rebalance tree. */
  rb_link_node(&data->my_node, parent, tmp);
  rb_insert_color(&data->my_node, root); 

  return 0;
} 

void my_delete(struct rb_root *root, int num)
{
  struct mytype *data = my_search(root, num);
  if (!data) {
  fprintf(stderr, "Not found %d.\n", num);
  return;
  } 

  rb_erase(&data->my_node, root);
  free(data);
} 

void print_rbtree(struct rb_root *tree)
{
  struct rb_node *node; 

  for (node = rb_first(tree); node; node = rb_next(node))
  printf("%d ", rb_entry(node, struct mytype, my_node)->num); 

  printf("\n");
} 

int main(int argc, char *argv[])
{
  struct rb_root mytree = RB_ROOT;
  int i, ret, num;
  struct mytype *tmp; 

  if (argc < 2) {
  fprintf(stderr, "Usage: %s num\n", argv[0]);
  exit(-1);
  } 

  num = atoi(argv[1]); 

  printf("Please enter %d integers:\n", num);
  for (i = 0; i < num; i++) {
  tmp = malloc(sizeof(struct mytype));
  if (!tmp)
    perror("Allocate dynamic memory"); 

  scanf("%d", &tmp->num); 

  ret = my_insert(&mytree, tmp);
  if (ret < 0) {
    fprintf(stderr, "The %d already exists.\n", tmp->num);
    free(tmp);
  }
  } 

  printf("\nthe first test\n");
  print_rbtree(&mytree); 

  my_delete(&mytree, 21); 

  printf("\nthe second test\n");
  print_rbtree(&mytree); 

  return 0;
} 

编译并执行:

$ gcc rbtree.c test.c -o test
richard@tanglinux:~/algorithm/redblack$ ./test 10
Please enter 10 integers:
23
4
56
32
89
122
12
21
45
23
The 23 already exists. 

the first test
4 12 21 23 32 45 56 89 122  

the second test
4 12 23 32 45 56 89 122  

七、总结

以上就是关于Linux内核中红黑树算法实现的全部内容,文章介绍的很详细,希望对大家的工作和学习能有所帮助,如果有疑问可以留言交流。

(0)

相关推荐

  • Linux内核启动参数详解

    1.环境: Ubuntu 16.04 Linux linuxidc 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 2.查看当前linux内核的启动参数: cat /proc/cmdline 笔者的输出内容如下: BOOT_IMAGE=/boot/vmlinuz-4.4.0-89-generic root=UUID=bef418fa-4202-4513-b39

  • Linux内核漏洞浅析

    与Windows相比,Linux被认为具有更好的安全性和其他扩展性能.这些特性使得Linux在操作系统领域异军突起,得到越来越多的重视.随着Linux应用量的增加,其安全性也逐渐受到了公众甚或黑客的关注.那么,Linux是否真的如其支持厂商们所宣称的那样安全呢?本期我们请到了启明星辰信息技术有限公司积极防御实验室工程师赵伟,对Linux进行专业的漏洞技术分析. Linux内核精短.稳定性高.可扩展性好.硬件需求低.免费.网络功能丰富.适用于多种cpu等特性,使之在操作系统领域异军突起.其独特的魅

  • 一张图看尽Linux内核运行原理

    众所周知的是,几乎整个互联网都运行在 Linux 上,从网络协议,到服务器,到你平常访问的绝大多数网站,都能看到它的身影.Linux 内核就是最复杂最流行的开源项目之一.如果你希望学习内核知识,在网上可以搜到无数的资料,但是 Linux 内核还是一个非常难弄明白的项目. 俗话说:一图胜千言,今天我们就为大家介绍一张完整的 Linux 内核运行原理图,通过这张图,你可以很方便地学习内核知识. 在 Linux 内核中,有许多层次.模块.功能调用和函数:要把其中的每一块儿都弄明白很不容易,不过 Mak

  • Linux内核模块和驱动的编写

    Linux内核是一个整体是结构,因此向内核添加任何东西,或者删除某些功能,都十分困难.为了解决这个问题引入了内核机制.从而可以动态的想内核中添加或者删除模块. 模块不被编译在内核中,因而控制了内核的大小.然而模块一旦被插入内核,他就和内核其他部分一样.这样一来就会曾家一部分系统开销.同时,如果模块出现问题,也许会带来系统的崩溃. 模块的实现机制: 启动时,由函数 void inti_modules() 来初始化模块,因为启动事很多时候没有模块.这个函数往往把内核自身当作一个虚模块. 如由系统需要

  • Linux内核链表实现过程

    关于双链表实现,一般教科书上定义一个双向链表节点的方法如下: 复制代码 代码如下: struct list_node{stuct list_node *pre;stuct list_node *next;ElemType data; } 即一个链表节点包含:一个指向前向节点的指针.一个指向后续节点的指针,以及数据域共三部分.但查看linux内核代码中的list实现时,会发现其与教科书上的方法有很大的差别.来看看linux是如何实现双链表.双链表节点定义 复制代码 代码如下: struct lis

  • 解析Linux内核的基本的模块管理与时间管理操作

    内核模块管理 Linux设备驱动会以内核模块的形式出现,因此学会编写Linux内核模块编程是学习linux设备驱动的先决条件. Linux内核的整体结构非常庞大,其包含的组件非常多.我们把需要的功能都编译到linux内核,以模块方式扩展内核功能. 先来看下最简单的内核模块 #include <linux/init.h> #include <linux/module.h> static int __init hello_init(void) { printk(KERN_ALERT &

  • 浅谈Linux内核创建新进程的全过程

    进程描述 进程描述符(task_struct) 用来描述进程的数据结构,可以理解为进程的属性.比如进程的状态.进程的标识(PID)等,都被封装在了进程描述符这个数据结构中,该数据结构被定义为task_struct 进程控制块(PCB) 是操作系统核心中一种数据结构,主要表示进程状态. 进程状态 fork() fork()在父.子进程各返回一次.在父进程中返回子进程的 pid,在子进程中返回0. fork一个子进程的代码 #include <stdio.h> #include <stdli

  • SYN Cookie在Linux内核中的实现

    概述 在目前以IPv4为支撑的网络协议上搭建的网络环境中,SYN Flood是一种非常危险而常见的DoS攻击方式.到目前为止,能够有效防范SYN Flood攻击的手段并不多,而SYN Cookie就是其中最著名的一种.SYN Cookie原理由D. J. Bernstain和 Eric Schenk发明.在很多操作系统上都有各种各样的实现.其中包括Linux.本文就分别介绍一下SYN Flood攻击和SYN Cookie的原理,更重要的是介绍Linux内核中实现SYN Cookie的方式.最后,

  • Linux内核中红黑树算法的实现详解

    一.简介 平衡二叉树(BalancedBinary Tree或Height-Balanced Tree) 又称AVL树.它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1.若将二叉树上结点的平衡因子BF(BalanceFactor)定义为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有结点的平衡因子只可能是-1.0和1.(此段定义来自严蔚敏的<数据结构(C语言版)>) 红黑树 R-B Tree,全称是Red-B

  • C++ 操作系统内存分配算法的实现详解

    目录 一.实验目的 二.实验内容 三.实验要求 四.代码实现 五.测试样例 一.实验目的 通过本实验帮助学生理解在动态分区管理方式下应怎样实现主存空间的分配和回收. 二.实验内容 在动态分区管理方式下采用不同的分配算法实现主存分配和实现主存回收. 三.实验要求 (1)可变分区方式是按作业需要的主存空间大小来分割分区的.当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业:若无,则作业不能装入.随着作业的装入.撤离.主存空间被分成许多个分区,有

  • 应用OpenCV和Python进行SIFT算法的实现详解

    应用OpenCV和Python进行SIFT算法的实现 如下图为进行测试的gakki101和gakki102,分别验证基于BFmatcher.FlannBasedMatcher等的SIFT算法,对比其优劣.为体现出匹配效果对于旋转特性的优势,将图gakki101做成具有旋转特性的效果. 基于BFmatcher的SIFT实现 BFmatcher(Brute-Force Matching)暴力匹配,应用BFMatcher.knnMatch( )函数来进行核心的匹配,knnMatch(k-nearest

  • Linux内存描述符mm_struct实例详解

    Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起.(所依据的代码是2.6.32.60) 无论是内核线程还是用户进程,对于内核来说,无非都是task_struct这个数据结构的一个实例而已,task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context.其中有一个被称为'内存描述符'(memory descriptor)的数据结构mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息

  • Linux共享内存实现机制的详解

    Linux共享内存实现机制的详解 内存共享: 两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间.进程A可以即时看到进程B对共享内存中数据的更新,反之亦然.由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以. 效率: 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]: 一次从输入文件到

  • Linux消息队列实现进程间通信实例详解

    Linux消息队列实现进程间通信实例详解 一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度. 二.在Linux中使用消息队列 Linux提供了一系列消息队列的函数接口来让我们方便地使用

  • Linux中selinux基础配置教程详解

    selinux(Security-Enhanced Linux)安全增强型linux,是一个Linux内核模块,也是Linux的一个安全子系统. 三种模式: Enforcing:强制模式,在selinux运作时,已经开始限制domain/type. permissive: 警告模式,在selinux运作时,会有警告讯息,但不会限制domain/type的存取. disabled: 关闭模式. 可用getenforce查看selinux状态 selinux对文件的作用: 当开启selinux后,s

  • Linux应用调试之strace命令详解

    1.strace简介 strace常用来跟踪进程执行时的系统调用和所接收的信号. 通过strace可以知道应用程序打开了哪些文件,以及读写了什么内容,包括消耗的时间以及返回值等.在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备.strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间. 2.安装strace命令 首先需要以下两个文件: strace-4.5

  • Linux系统诊断之内存基础深入详解

    1.背景 谈及linux内存,很多时候,我们会关注free,top等基础命令.当系统遇到异常情况时,内存问题的根因追溯,现场诊断时,缺乏深层次的debug能力.本篇幅不做深层讨论,能把当前系统的问题描述清楚,是每个SRE应该具备的最基础能力. 2. free 2.1 free命令原理 free是通过查看 /proc/meminfo 来获取内存的使用情况.但是 /proc/meminfo 这个文件又是怎么来的?我们先了解下 /proc 目录: /proc 是一个虚拟文件系统,该目录下的所有文件都是

  • Java中内核线程理论及实例详解

    1.概念 内核线程是直接由操作系统内核控制的,内核通过调度器来完成内核线程的调度并负责将其映射到处理器上执行.内核态下的线程执行速度理论上是最高的,但是用户不会直接操作内核线程,而是通过内核线程的接口--轻量级进程来间接的使用内核线程.这种轻量级进程就是所谓的线程. 2.优点 由于内核线程的支持,每一个线程都是一个独立的单元,因此就算某一个线程挂掉了,也不会导致整个进程挂掉. 3.缺点 这种实现方式也存在局限性.由于是基于内核线程实现的,所以当涉及到线程的操作时(创建.运行.切换等)就涉及到系统

随机推荐