kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

内核线程使用

http://blog.csdn.net/newnewman80/article/details/7050090

kthread_create:创建线程。
1
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);

线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct指针传给wake_up_process(),然后通过此函数运行线程。

kthread_run :创建并启动线程的函数:
1
struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,const char *namefmt, ...);
kthread_stop:通过发送信号给线程,使之退出。
1
int kthread_stop(struct task_struct *thread);

线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit函数,或者其他的进程调用kthread_stop函数,结束线程的运行。
但如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。

1. 头文件

1
2
3
#include <linux/sched.h>       //wake_up_process()
#include <linux/kthread.h>      //kthread_create()、kthread_run()   
#include <err.h>                //IS_ERR()、PTR_ERR()  

2. 实现

2.1创建线程

kernel thread可以用kernel_thread创建,但是在执行函数里面必须用daemonize释放资源并挂到init下,还需要用completion等待这一过程的完成。为了简化操作kthread_create闪亮登场。 在模块初始化时,可以进行线程的创建。使用下面的函数和宏定义:

1
2
3
struct task_struct *kthread_create(int (*threadfn)(void *data),     
					void *data,  
					const char namefmt[], ...);  
1
2
3
4
5
6
7
8
#define kthread_run(threadfn, data, namefmt, ...)                      \
({                                                                     \
	struct task_struct *__k                                            \
		   = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__);  \
	if (!IS_ERR(__k))                                                  \
		   wake_up_process(__k);                                       \
	__k;                                                               \
})  

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static struct task_struct *test_task;  
static int test_init_module(void)  
{  
	int err;  
	test_task = kthread_create(test_thread, NULL, "test_task");  
	if (IS_ERR(test_task)) {  
		printk("Unable to start kernel thread./n");  
		err = PTR_ERR(test_task);  
		test_task = NULL;  
		return err;  
	}  
	wake_up_process(test_task);  
	return 0;  
}  
module_init(test_init_module);  
2.2线程函数

在线程函数里,完成所需的业务逻辑工作。主要框架如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int threadfunc(void *data) {
	...        
	while(1) {
		set_current_state(TASK_UNINTERRUPTIBLE);
		if (kthread_should_stop()) break;
		if () { //条件为真
			//进行业务处理
		} else { //条件为假
			//让出CPU运行其他线程,并在指定的时间内重新被调度
			schedule_timeout(HZ);
		}
	}
	...
	return 0;
}
2.3结束线程

在模块卸载时,可以结束线程的运行。使用下面的函数:

1
int kthread_stop(struct task_struct *k);

例如:

1
2
3
4
5
6
7
8
static void test_cleanup_module(void)  
{  
	if (test_task) {  
		kthread_stop(test_task);  
		test_task = NULL;  
	}  
}  
module_exit(test_cleanup_module);  

设置普通线程优先级

1
2
void set_user_nice(struct task_struct *p, long nice);
// -20 <= nice < 20

将线程设置为实时线程并设置优先级

1
2
3
4
int sched_setscheduler(struct task_struct *p, int policy, struct sched_param *param);
struct sched_param {
	int sched_priority; // 实时线程对应区间[1, 99]
};

CFS 调度模块(在 kernel/sched_fair.c 中实现)用于以下调度策略:SCHED_NORMAL、SCHED_BATCH 和 SCHED_IDLE。
对于 SCHED_RR 和 SCHED_FIFO 策略,将使用实时调度模块(该模块在 kernel/sched_rt.c 中实现)。

top中NI, PR

NI,nice,动态修正CPU调度。范围(-20~19)。越大,cpu调度越一般,越小,cpu调度越偏向它。一般用于后台进程,调整也是往大了调,用来给前台进程让出CPU资源。命令行下可以用renice设置。

PR:优先级,会有两种格式,一种是数字(默认20),一种是RT字符串。

PR默认是20,越小,优先级越高。修改nice可以同时修改PR,测试过程:先开一个窗口,运行wc,另开一个窗口运行top,按N按照PID倒序排,按r输入要renice的PID,然后输入-19~20之间的值,可以看到NI变成输入的值,PR=PR+NI。修改NI得到PR的范围是0~39。优先级由高到低

RT是real-time。只能用chrt -p (1~99) pid来修改。chrt -p 1 1234会将1234的PR改成-2,chrt -p 98 1234变成-99。chrt -p 99 1234会变成RT……只要chrt过,修改nice后PR不会再更改。修改chrt得到的PR范围是RT~-2。优先级由高到低

NUMA技术相关笔记

http://blog.csdn.net/jollyjumper/article/details/17168175

起源于在mongo启动脚本中看到numactl --interleave=all mongod ...

NUMA,非统一内存访问(Non-uniform Memory Access),介于SMP(对称多处理)和MPP(大规模并行处理)之间,各个节点自有内存(甚至IO子系统),访问其它节点的内存则通过高速网络通道。NUMA信息主要通过BIOS中的ACPI(高级配置和编程接口)进行配置,Linux对NUMA系统的物理内存分布信息从系统firmware的ACPi表中获得,最重要的是SRAT(System Resource Affinity Table)和SLIT(System locality Information Table)表。SRAT表包含CPU信息、内存相关性信息,SLIT表则记录了各个节点之间的距离,在系统中由数组node_distance[]记录。这样系统可以就近分配内存,减少延迟。

Linux中用一个struct pg_data_t表示一个numa节点,Linux内核支持numa调度,并实现CPU的负载均衡。

查看是否支持:

dmesg | grep -i numa

要查看具体的numa信息用numastat
1
2
3
4
5
6
7
8
numastat
	                       node0           node1
numa_hit             19983469427     20741805466
numa_miss             1981451471      2503049250
numa_foreign          2503049250      1981451471
interleave_hit         849781831       878579884
local_node           19627390917     20298995632
other_node            2337529981      2945859084

numa_hit是打算在该节点上分配内存,最后从这个节点分配的次数;
num_miss是打算在该节点分配内存,最后却从其他节点分配的次数;
num_foregin是打算在其他节点分配内存,最后却从这个节点分配的次数;
interleave_hit是采用interleave策略最后从该节点分配的次数;
local_node该节点上的进程在该节点上分配的次数
other_node是其他节点进程在该节点上分配的次数

lscpu可以看到两个node的cpu归属:
1
2
3
4
lscpu
...
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30
NUMA node1 CPU(s):     1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31
numactl --hardware命令

会返回不同节点的内存总大小,可用大小,以及node distance等信息。

各个cpu负载情况,使用命令:mpstat -P ALL(需要安装sysstat)

Linux上使用numactl设定进程的numa策略。常见的情况是,数据库daemon进程(mongodb,mysql)可能会吃掉很多内存,而一个numa节点上的内存很有限,内存不够时虚拟内存频繁与硬盘交换数据,导致性能急剧下降(标识是irqbalance进程top中居高不下),这时应该采用interleave的numa策略,允许从其他节点分配内存。

各个内存的访问延迟如何?numactl man中的example提供了参考,我在公司的服务器上测了一下:

写速度:
1
2
3
4
5
6
7
8
9
10
numactl --cpubind=0 --membind=0 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024

1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.546679 s, 2.0 GB/s

numactl --cpubind=0 --membind=1 dd if=/dev/zero of=/dev/shm/A bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.612825 s, 1.8 GB/s
读速度:

测试从同一个节点读取:

1
2
3
4
5
numactl --cpubind=0 --membind=0 dd if=/dev/zero of=/dev/shm/A bs=1M count=1000
date +%s.%N
numactl --cpubind=0 --membind=0 cp /dev/shm/A /dev/null
date +%s.%N
rm /dev/shm/A

花费0.264556884765625秒,速度是3.779905410081901GB/s。

从另一个节点读取:

1
2
3
4
5
numactl --cpubind=0 --membind=0 dd if=/dev/zero of=/dev/shm/A bs=1M count=1000
date +%s.%N
numactl --cpubind=1 --membind=1 cp /dev/shm/A /dev/null
date +%s.%N
rm /dev/shm/A

花费0.3308408260345459秒,速度是3.022601569419312GB/s。

加速效果还是很明显的。

参考:

http://www.ibm.com/developerworks/cn/linux/l-numa/
http://www.dedecms.com/knowledge/data-base/nosql/2012/0820/8684.html

玩转CPU Topology

http://www.searchtb.com/2012/12/%E7%8E%A9%E8%BD%ACcpu-topology.html

先温习几个概念

请原谅对部分术语笔者直接引用了wikipedia上的英文解释,因为哥实在做不到比wikipedia上更准确描述。我会试着解释部分的术语,并在本节的最后梳理一下这些术语之间的关系。注意,笔者对由于不准确的描述导致的性能下降,进程crash等任何问题不承担任何责任☺

NUMA:Non-Uniform Memory Access (NUMA) is a computer memory design used in multiprocessing, where the memory access time depends on the memory location relative to a processor. Under NUMA, a processor can access its own local memory faster than non-local memory, that is, memory local to another processor or memory shared between processors.NUMA architectures logically follow in scaling from symmetric multiprocessing (SMP) architectures.

提到NUMA就不能不对比SMP,

SMP:Symmetric multiprocessing (SMP) involves a multiprocessor computer hardware architecture where two or more identical processors are connected to a single shared main memory and are controlled by a single OS instance.

说了这么多其实都是为了介绍NUMA Node:

A fairly technically correct and also fairly ugly definition of a node is: a region of memory in which every byte has the same distance from each CPU.
A more common definition is: a block of memory and the CPUs, I/O, etc. physically on the same bus as the memory.

CPU:这个不解释,原因你懂得。想当年CPU拼的是频率,频率越高越NB,但是提升频率和制程密切相关。

Intel cpu制程
但是制程这玩意有一个物理天花板,提升越来越难,有报道指出,现阶段普遍应用的硅晶体管在尺寸上有一个10nm的物理极限。为了提升性能cpu走上了多核的道路,即在一个封装(socket或者processor)里放多个core。这还不够,又发明了超线程技术Hyper-threading

HT:HT Technology is used to improve parallelization of computations (doing multiple tasks at once) performed on PC microprocessors. For each processor core that is physically present, the operating system addresses two virtual or logical cores, and shares the workload between them when possible. They appear to the OS as two processors, thus the OS can schedule two processes at once. 一个core 在HT之后OS看到的就是2个Logical Processor。

下图展示了这些术语之间的逻辑关系:

cpu 概念逻辑关系

一个NUMA node包括一个或者多个Socket,以及与之相连的local memory。一个多核的Socket有多个Core。如果CPU支持HT,OS还会把这个Core看成 2个Logical Processor。为了避免混淆,在下文中统一用socket指代Processor or Socket;为了偷懒,下文中用Processor指代Logical Processor,击键能省则省不是。

查看CPU Topology

本文以笔者能访问的某台Red Hat Enterprise Linux Server release 5.4为例介绍,其他系统请自行google。

NUMA Node

第一种方法使用numactl查看

1
2
3
4
5
6
7
8
9
10
numactl --hardware
available: 2 nodes (0-1)  //当前机器有2个NUMA node,编号0&1
node 0 size: 12091 MB  //node 0 物理内存大小
node 0 free: 988 MB    //node 0 当前free内存大小
node 1 size: 12120 MB
node 1 free: 1206 MB
node distances:        //node 距离,可以简单认为是CPU本node内存访问和跨node内存访问的成本。从下表可知跨node的内存访问成本(20)是本地node内存(10)的2倍。
node   0   1
  0:  10  20
  1:  20  10

第二种方法是通过sysfs查看,这种方式可以查看到更多的信息

1
2
ls /sys/devices/system/node/
1

node0 node1 //两个目标表示本机有2个node,每个目录内部有多个文件和子目录描述node内cpu,内存等信息。比如说node0/meminfo描述了node0内存相关信息。

Socket

可以直接通过/proc/cpuinfo查看,cpuinfo里的physical id描述的就是Socket的编号,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cat /proc/cpuinfo | grep "physical id"
physical id     : 0
physical id     : 0
physical id     : 0
physical id     : 0
physical id     : 1
physical id     : 1
physical id     : 1
physical id     : 1
physical id     : 0
physical id     : 0
physical id     : 0
physical id     : 0
physical id     : 1
physical id     : 1
physical id     : 1
physical id     : 1

由上可知本机有2个Socket,编号为0和1。 还可以简单的使用如下命令直接查看Socket个数

1
2
cat /proc/cpuinfo|grep "physical id" | sort -u | wc –l
2   //本机有2个物理CPU封装
Core

仍然是可以通过/proc/cpuinfo查看,cpuinfo中跟core相关的信息有2行。

1
2
cpu cores : 4 //一个socket有4个核,
core id : 1 //一个core在socket内的编号

通过如下命令可以直接查看core的数量

1
2
cat /proc/cpuinfo | grep "cpu cores" | uniq | cut -d: -f2
4  //1个socket有4个core
  • 本机有2个socket,每个有4个core,所以一共有8个core

还可以查看core在Socket里的编号

1
2
3
4
5
cat /proc/cpuinfo | grep "core id" | sort -u
core id         : 0
core id         : 1
core id         : 10
core id         : 9

一个socket里面4个core的编号为0,1,9,10。是的,core id是不连续的。如果谁知道为啥麻烦通知我,先谢了。

Logical Processor

仍然是可以通过/proc/cpuinfo查看在OS的眼里有多少个Logical Processor

1
2
cat /proc/cpuinfo | grep processor | wc –l
16

Ok,8个core变成了16个Logical Processor,所以本机开启了HT。

问题来了,cpuinfo里面16个Processor编号为0-15,Core的id为0,1,9,10,Socket的id为0,1。这些编号是如何对应的呢?

我们查看一个Processor完整的cpuinfo就比较清楚了,我剔除了不相关的行:

1
2
3
4
5
6
7
8
processor : 0    processor : 5
physical id : 0
siblings : 8
core id : 0
cpu cores : 4     physical id : 1
siblings : 8
core id : 1
cpu cores : 4

明白了?
Processor 0:在socket 0的core 0 里。
Processor 5:在socket 1的core 1 里。

Cache

仍然可以通过/proc/cpuinfo查看,OMG, cpuinfo难道是万能的?

1
2
3
processor       : 0
cache size      : 12288 KB //cpu cache 大小
cache_alignment : 64 

问题又来了,我们知道CPU cache分为L1,L2,L3, L1一般还分为独立的指令cache和数据cache。Cpuinfo里这个cache size指的是?

好吧,cpuinfo也不是万能的。详细的cache信息可以通过sysfs查看

1
2
ls /sys/devices/system/cpu/cpu0/cache/
index0  index1  index2  index3

4个目录
index0: 1级数据cache
index1: 1级指令cache
index2: 2级cache
index3: 3级cache ,对应cpuinfo里的cache

目录里的文件是cache信息描述,以本机的cpu0/index0为例简单解释一下:

文件 内容 说明
type Data 数据cache,如果查看index1就是Instruction
Level 1 L1
Size 32K 大小为32K
coherency_line_size 64 64*4*128=32K
physical_line_partition 1
ways_of_associativity 4
number_of_sets 128
shared_cpu_map 00000101 表示这个cache被CPU0和CPU8 share

解释一下shared_cpu_map内容的格式:
表面上看是2进制,其实是16进制表示,每个bit表示一个cpu,1个数字可以表示4个cpu
截取00000101的后4位,转换为2进制表示

CPU id 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0×0101的2进制表示 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1

0101表示cpu8和cpu0,即cpu0的L1 data cache是和cpu8共享的。
验证一下?

1
2
cat /sys/devices/system/cpu/cpu8/cache/index0/shared_cpu_map
00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000101

再看一下index3 shared_cpu_map的例子

1
2
cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_map
00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000f0f
CPU id 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0x0f0f的2进制表示 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1

cpu0,1,2,3和cpu8,9,10,11共享L3 cache

小结

综合以上信息可以绘制出以下的cpu topology图:

抱歉,图比较大,网页上看不清楚,下面放大单node图,另一个node基本上可以类推。

使用CPU Topology

好吧,现在我们知道了如何查看CPU topology。那么这与各位攻城狮的工作有什么关系呢?

以淘宝搜索常见的服务模型为例,服务端把离线处理的数据load到内存中,开始监听某个服务端口,接收到客户端请求后从线程池中分配一个工作线程,该线程解析请求,读取内存中对应的数据,进行一些计算,然后把结果返回给客户端。

把这个过程简化简化再简化,抽象抽象再抽象,可以得到一个简单的测试程序,程序流程为:
1. 主线程申请2块256M的内存,使用memset初始化这两块内存的每个byte
2. 启动2个子线程,每个线程内循环16M次,在每次循环中随机读取2块内存中的各1K数据,对每个byte进行简单加和,返回。
3. 主线程等待子线程结束,打印每个线程的结果,结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

char *p1, *p2;

int run(unsigned r)
{
	    int i,j,k,ret=0;
	    unsigned r1,r2;
	    srand(r);
	    for (i=0;i<(16<<20);i++) {
	            r1 = (unsigned)(rand() % ((256<<20)-(1<<10)));
	            r2 = (unsigned)(rand() % ((256<<20)-(1<<10)));
	            k = 0;
	            for (j=0;j<(1<<10);j++) {
	                    k += *(p1+r1+j);
	                    k += *(p2+r2+j);
	            }
	            ret += k;
	    }
	    return ret;
}

int main()
{
	    int i,j;
	    pthread_t pth1, pth2;
	    p1 = (char*)malloc(256<<20);
	    p2 = (char*)malloc(256<<20);
	    memset(p1, sizeof(p1), 0);
	    memset(p2, sizeof(p2), 0);
	    pthread_create(&pth1, NULL, run, 123);
	    pthread_create(&pth2, NULL, run, 456);
	    pthread_join(pth1, NULL);
	    pthread_join(pth2, NULL);
	    return 0;
}

使用-O2编译出可执行文件test,分别使用下面2个命令运行该程序。运行时间和机器配置以及当前load有关,绝对值没有意义,这里仅比较相对值。

命令 time ./test time numactl -m 0 –physcpubind=2,3 ./test
用时 real 0m38.678s
user 1m6.270s
sys 0m5.569s
real 0m28.410s
user 0m54.997s
sys 0m0.961s

发生了什么?为什么有这么大的差异? 第一个命令直观,那么我们看一下第二个命令具体做了什么:

1
2
3
numactl -m 0 --physcpubind=2,3 ./test
-m 0:在node 0上分配内存
--physcpubind=2,3:在cpu 2和3上运行程序,即一个线程运行在cpu2上,另一个运行在cpu3上。

参考上面的CPUtopology图就很容易理解了,由于线程绑定cpu2和3执行,共享了L3 cache,且全部内存都是本node访问,运行效率自然比随机选择cpu运行,运行中还有可能切换cpu,内存访问有可能跨node的第一种方式要快了。

接下来,让我们看看完整的表格,读者可以看看有没有惊喜:

情况 命令 用时 解释
完全由OS控制 time ./test real 0m38.678s
user 1m6.270s
sys 0m5.569s
乐观主义者,甩手掌柜型
绑定跨node的Cpu执行 time numactl –physcpubind=2,6 ./test real 0m38.657s
user 1m7.126s
sys 0m5.045s
Cpu 2和6不在同一个node,不能share L3 cache
绑定单node的Cpu执行 time numactl –physcpubind=2,3 ./test real 0m28.605s
user 0m55.161s
sys 0m0.856s
Cpu 2和3在同一个node,share L3 cache。内存使用由OS控制,一般来说node 0和1内存都会使用。
跨node内存访问+绑定单node CPU执行 time numactl -m 1 –physcpubind=2,3 ./test real 0m33.218s
user 1m4.494s
sys 0m0.911s
内存全使用node1,2个cpu在node0,内存访问比较吃亏
单node内存访问+绑定本node CPU执行 time numactl -m 0 –physcpubind=2,3 ./test real 0m28.367s
user 0m55.062s
sys 0m0.825s
内存&cpu都使用node0
单node内存访问+绑定本node 单core执行 time numactl -m 0 –physcpubind=2,10 ./test real 0m58.062s
user 1m55.520s
sys 0m0.270s
CPU2和10不但在同一个node,且在同一个core,本意是希望共享L1,L2cache,提升性能。但是不要忘了,CPU2和10是HT出来的logical Processor,在本例cpu密集型的线程中硬件争用严重,效率急剧下降。有没有发现和上一个case的时间比率很有意思?

现在谁还能说了解点cpu topology没用呢?☺

Tips

补充几个小tips,方便有兴趣的同学分析上面表格的各个case

1.查看进程的内存numa node分布

简单的说可以查看进程的numa_maps文件

1
cat /proc/pid/numa_maps

文件格式可以直接:man numa_maps
为了避免输入数字pid,我使用如下命令查看:

1
cat /proc/$(pidof test|cut –d” ” -f1)/numa_maps
2.查看线程run在哪个processor

可以使用top命令查看一个进程的各个线程分别run在哪个processor上
同样,为了避免输入数字pid,我使用如下命令启动top:

1
top -p$(pidof test |sed -e ‘s/ /,/g’)

在默认配置下不显示线程信息,需要进入Top后按“shift+H”,打开线程显示。
另外,如果没有P列,还需要按“f”,按“j”,添加,这一列显示的数字就是这个线程上次run的processor id。
关于top的使用,请读者自行man top

3.另一种绑定cpu执行的方法

如果读者的程序不涉及大量内存的访问,可以通过taskset绑定cpu执行。别怪我没提醒你,仔细判断是否应该绑定到同一个core的processor上哦。
关于命令的使用,请读者自行Man taskset

隐藏权限--无法添加用户和组等

执行命令:

1
2
[root@localhost softwaretools]# groupadd mysql
groupadd:无法打开组文件(groupadd: unable to open group file)

此时就奇怪了,当前用的明明是root用户,为什么没有创建组和用户的权限呢。

结论: 1,添加用户需要用到passwd和shadow这两个文件
2,添加组需要用到shadow和gshadow这两个文件

使用 ls -l 命令发现权限正常。

最终发现问题,找到了2个命令(lsattr和chattr),是因为隐藏权限在作怪:
对这2个命令的简单做下说明:
对于某些有特殊要求的档案(如服务器日志)还可以追加隐藏权限的设定。这些隐藏权限包括: Append only (a), compressed ©, no dump (d), immutable (i), data journalling (j),secure deletion (s), no tail-merging (t), undeletable (u), no atime updates (A), synchronous directory updates (D), synchronous updates (S), and top of directory hierarchy (T).
lsattr命令是查看隐藏权限设定情况的,chattr是变更隐藏权限的命令。

首先使用使用lsattr查看了一下这几个文件:

1
2
3
4
5
6
7
8
[root@localhost ~]# lsattr /etc/passwd  
------------- /etc/passwd  
[root@localhost ~]# lsattr /etc/group  
----i-------- /etc/group  
[root@localhost ~]# lsattr /etc/shadow  
------------- /etc/shadow  
[root@localhost ~]# lsattr /etc/gshadow  
----i-------- /etc/gshadow  

可以看到文件被设置的 i 这个隐藏权限,
i:设定文件不能被删除、改名、设定链接关系,同时不能写入或新增内容。
i参数对于文件 系统的安全设置有很大帮助。

既然这样只要把i权限去掉就应该好了。

使用命令chattr命令修改文件隐藏权限,执行如下命令:

1
2
chattr -i /etc/gshadow
chattr -i /etc/group

然后可以正常执行了。

Linux的IPC命令 查看共享内存

http://www.cnblogs.com/cocowool/archive/2012/05/22/2513027.html

进程间通信概述

进程间通信有如下的目的:
1、数据传输,一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M之间;
2、共享数据,多个进程想要操作共享数据,一个进程对数据的修改,其他进程应该立刻看到;
3、通知事件,一个进程需要向另一个或一组进程发送消息,通知它们发生了某件事情;
4、资源共享,多个进程之间共享同样的资源。为了做到这一点,需要内核提供锁和同步机制;
5、进程控制,有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

Linux进程间通信由以下几部分发展而来:
早期UNIX进程间通信:包括管道、FIFO、信号。
基于System V的进程间通信:包括System V消息队列、System V信号灯(Semaphore)、System V共享内存。
基于Socket进程间通信。
基于POSIX进程间通信:包括POSIX消息队列、POSIX信号灯、POSIX共享内存。
Linux中,与IPC相关的命令包括:ipcs、ipcrm(释放IPC)、

IPCS命令是Linux下显示进程间通信设施状态的工具。我们知道,系统进行进程间通信(IPC)的时候,可用的方式包括信号量、共享内存、消息队列、管道、信号(signal)、套接字等形式[2]。使用IPCS可以查看共享内存、信号量、消息队列的状态。

例如在CentOS6.0上执行ipcs

具体的用法总结如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1、显示所有的IPC设施
# ipcs -a

2、显示所有的消息队列Message Queue
# ipcs -q

3、显示所有的信号量
# ipcs -s

4、显示所有的共享内存
# ipcs -m

5、显示IPC设施的详细信息
# ipcs -q -i id
id 对应shmid、semid、msgid等。-q对应设施的类型(队列),查看信号量详细情况使用-s,查看共享内存使用-m。

6、显示IPC设施的限制大小
# ipcs -m -l
-m对应设施类型,可选参数包括-q、-m、-s。

7、显示IPC设施的权限关系
# ipcs -c
# ipcs -m -c
# ipcs -q -c
# ipcs -s -c

8、显示最近访问过IPC设施的进程ID。
# ipcs -p
# ipcs -m -p
# ipcs -q -p

9、显示IPC设施的最后操作时间
# ipcs -t
# ipcs -q -t
# ipcs -m -t
# ipcs -s -t

10、显示IPC设施的当前状态
# ipcs -u

Linux上的ipcs命令,不支持UNIX上的-b、-o指令,同样UNIX中不支持-l、-u指令,所以在编写跨平台的脚本时,需要注意这个问题。

参考资料:

1、Linux下IPCS的用法详解
2、Linux进程间通信
3、Linux下IPCS的10种用法
4、Linux IPC小结
5、Linux IPC总结