磁盘文件的原子与竞争关系 linux现代操作系统支持多任务的并发 , 并发在提高计算资源利用率的同时也带来了资源竞争的问题 。例如C语言语句“count;”在未经编译器优化时生成的汇编代码为 。
当操作系统内存在多个进程同时执行这段代码时,就可能带来并发问题 。
假设count变量初始值为0 。进程1执行完“mov eax, [count]”后,寄存器eax内保存了count的值0 。此时,进程2被调度执行,抢占了进程1的CPU的控制权 。进程2执行“count;”的汇编代码,将累加后的count值1写回到内存 。然后 , 进程1再次被调度执行,CPU控制权回到进程1 。进程1接着执行,计算count的累加值仍为1,写回到内存 。虽然进程1和进程2执行了两次“count;”操作,但是count实际的内存值为1,而不是2!
单处理器原子操作
解决这个问题的方法是,将“count;”语句翻译为单指令操作 。
Intel x86指令集支持内存操作数的inc操作,这样“count;”操作可以在一条指令内完成 。因为进程的上下文切换是在总是在一条指令执行完成后,所以不会出现上述的并发问题 。对于单处理器来说 , 一条处理器指令就是一个原子操作 。
多处理器原子操作
但是在多处理器的环境下,例如SMP架构,这个结论不再成立 。我们知道“inc [count]”指令的执行过程分为三步:
1)从内存将count的数据读取到cpu 。
2)累加读取的值 。
3)将修改的值写回count内存 。
这又回到前面并发问题类似的情况,只不过此时并发的主题不再是进程,而是处理器 。
Intel x86指令集提供了指令前缀lock用于锁定前端串行总线(FSB),保证了指令执行时不会受到其他处理器的干扰 。
使用lock指令前缀后,处理器间对count内存的并发访问(读/写)被禁止,从而保证了指令的原子性 。
x86原子操作实现
Linux的源码中x86体系结构原子操作的定义文件为 。
linux2.6/include/asm-i386/atomic.h
文件内定义了原子类型atomic_t,其仅有一个字段counter,用于保存32位的数据 。
typedef struct { volatile int counter; } atomic_t;
其中原子操作函数atomic_inc完成自加原子操作 。
/**
* atomic_inc - increment atomic variable
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1.
*/
static __inline__ void atomic_inc(atomic_t *v)
{
__asm__ __volatile__(
LOCK "incl %0"
:"=m" (v-counter)
:"m" (v-counter));
}
其中LOCK宏的定义为 。
#ifdef CONFIG_SMP
#define LOCK "lock ; "
#else
#define LOCK ""
#endif
可见,在对称多处理器架构的情况下,LOCK被解释为指令前缀lock 。而对于单处理器架构,LOCK不包含任何内容 。
arm原子操作实现
在arm的指令集中,不存在指令前缀lock,那如何完成原子操作呢?
Linux的源码中arm体系结构原子操作的定义文件为 。
linux2.6/include/asm-arm/atomic.h
其中自加原子操作由函数atomic_add_return实现 。
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long tmp;
int result;
__asm__ __volatile__("@ atomic_add_return\n"
"1:ldrex%0, [%2]\n"
"add%0, %0, %3\n"
"strex%1, %0, [%2]\n"
"teq%1, #0\n"
"bne1b"
: "=r" (result), "=r" (tmp)
: "r" (v-counter), "Ir" (i)
: "cc");
【Linux命令nop linux命令nohub】return result;
}
上述嵌入式汇编的实际形式为 。
1:
ldrex[result], [v-counter]
add[result], [result], [i]
strex[temp], [result], [v-counter]
teq[temp], #0
bne1b
ldrex指令将v-counter的值传送到result,并设置全局标记“Exclusive” 。
add指令完成“result i”的操作 , 并将加法结果保存到result 。
strex指令首先检测全局标记“Exclusive”是否存在,如果存在,则将result的值写回counter-v , 并将temp置为0,清除“Exclusive”标记,否则直接将temp置为1结束 。
teq指令测试temp值是否为0 。
bne指令temp不等于0时跳转到标号1,其中字符b表示向后跳转 。
整体看来,上述汇编代码一直尝试完成“v-counter =i”的操作,直到temp为0时结束 。
使用ldrex和strex指令对是否可以保证add指令的原子性呢?假设两个进程并发执行“ldrex add strex”操作,当进程1执行ldrex后设定了全局标记“Exclusive” 。此时切换到进程2,执行ldrex前全局标记“Exclusive”已经设定,ldrex执行后重复设定了该标记 。然后执行add和strex指令 , 完成累加操作 。再次切换回进程1 , 接着执行add指令,当执行strex指令时,由于“Exclusive”标记被进程2清除,因此不执行传送操作,将temp设置为1 。后继teq指令测定temp不等于0,则跳转到起始位置重新执行,最终完成累加操作!可见ldrex和strex指令对可以保证进程间的同步 。多处理器的情况与此相同,因为arm的原子操作只关心“Exclusive”标记,而不在乎前端串行总线是否加锁 。
在ARMv6之前 , swp指令就是通过锁定总线的方式完成原子的数据交换,但是影响系统性能 。ARMv6之后,一般使用ldrex和strex指令对代替swp指令的功能 。
自旋锁中的原子操作
Linux的源码中x86体系结构自旋锁的定义文件为 。
linux2.6/include/asm-i386/spinlock.h
其中__raw_spin_lock完成自旋锁的加锁功能
#define __raw_spin_lock_string \
"\n1:\t" \
"lock ; decb %0\n\t" \
"jns 3f\n" \
"2:\t" \
"rep;nop\n\t" \
"cmpb $0,%0\n\t" \
"jle 2b\n\t" \
"jmp 1b\n" \
"3:\n\t"
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
__asm__ __volatile__(
__raw_spin_lock_string
:"=m" (lock-slock) : : "memory");
}
上述代码的实际汇编形式为 。
1:
lockdecb [lock-slock]
jns3
2:
repnop
cmpb$0, [lock-slock]
jle2
jmp1
3:
其中lock-slock字段初始值为1,执行原子操作decb后值为0 。符号位为0,执行jns指令跳转到3,完成自旋锁的加锁 。
当再次申请自旋锁时,执行原子操作decb后lock-slock值为-1 。符号位为1,不执行jns指令 。进入标签2,执行一组nop指令后比较lock-slock是否小于等于0,如果小于等于0回到标签2进行循环(自旋) 。否则跳转到标签1重新申请自旋锁 , 直到申请成功 。
自旋锁释放时会将lock-slock设置为1 , 这样保证了其他进程可以获得自旋锁 。
信号量中的原子操作
Linux的源码中x86体系结构自旋锁的定义文件为 。
linux2.6/include/asm-i386/semaphore.h
信号量的申请操作由函数down实现 。
/*
* This is ugly, but we want the default case to fall through.
* "__down_failed" is a special asm handler that calls the C
* routine that actually waits. See arch/i386/kernel/semaphore.c
*/
static inline void down(struct semaphore * sem)
{
might_sleep();
__asm__ __volatile__(
"# atomic down operation\n\t"
LOCK "decl %0\n\t"/* --sem-count */
"js 2f\n"
"1:\n"
LOCK_SECTION_START("")
"2:\tlea %0,%陎\n\t"
"call __down_failed\n\t"
"jmp 1b\n"
LOCK_SECTION_END
:"=m" (sem-count)
:
:"memory","ax");
}
实际的汇编代码形式为 。
lockdecl [sem-count]
js 2
1:
========== another section ==========
2:
lea[sem-count], eax
call__down_failed
jmp 1
信号量的sem-count一般初始化为一个正整数,申请信号量时执行原子操作decl,将sem-count减1 。如果该值减为负数(符号位为1)则跳转到另一个段内的标签2,否则申请信号量成功 。
标签2被编译到另一个段内,进入标签2后 , 执行lea指令取出sem-count的地址,放到eax寄存器作为参数,然后调用函数__down_failed表示信号量申请失败,进程加入等待队列 。最后跳回标签1结束信号量申请 。
信号量的释放操作由函数up实现 。
/*
* Note! This is subtle. We jump to wake people up only if
* the semaphore was negative (== somebody was waiting on it).
* The default case (no contention) will result in NO
* jumps for both down() and up().
*/
static inline void up(struct semaphore * sem)
{
__asm__ __volatile__(
"# atomic up operation\n\t"
LOCK "incl %0\n\t"/*sem-count */
"jle 2f\n"
"1:\n"
LOCK_SECTION_START("")
"2:\tlea %0,%陎\n\t"
"call __up_wakeup\n\t"
"jmp 1b\n"
LOCK_SECTION_END
".subsection 0\n"
:"=m" (sem-count)
:
:"memory","ax");
}
实际的汇编代码形式为 。
lockincl sem-count
jle2
1:
========== another section ==========
2:
lea[sem-count], eax
call__up_wakeup
jmp1
释放信号量时执行原子操作incl将sem-count加1,如果该值小于等于0,则说明等待队列有阻塞的进程需要唤醒,跳转到标签2,否则信号量释放成功 。
标签2被编译到另一个段内,进入标签2后,执行lea指令取出sem-count的地址,放到eax寄存器作为参数 , 然后调用函数__up_wakeup唤醒等待队列的进程 。最后跳回标签1结束信号量释放 。
linux怎么查看硬盘型号等信息df-TH硬盘信息free内存信息cat/proc/cpu****后面的用tab补齐我记得是cpuinfo但不确定cat/proc/meminfo也可以查看内存
几个常用的linux性能监控命令1. sar
每两秒刷新一次Linux命令nop , 总共5次
[root@dbhost01 ~]# sar 2 5
Linux 2.6.32-504.el6.x86_64 (dbhost01)03/30/2018_x86_64_ (4 CPU)
02:53:15 PMCPU\user%nice%system%iowait%steal%idle
02:53:17 PMall0.660.001.720.660.0096.96
02:53:19 PMall1.340.003.350.800.0094.51
02:53:21 PMall0.790.001.591.450.0096.17
02:53:23 PMall0.400.002.000.800.0096.80
02:53:25 PMall0.660.001.850.790.0096.70
Average:all0.770.002.100.900.0096.23
2. top
top -a 按照内存降序
[root@dbhost01 ~]# top -a
top - 15:00:54 up6:04,1 user,load average: 0.31, 0.19, 0.11
Tasks: 306 total,1 running, 305 sleeping,0 stopped,0 zombie
Cpu(s):7.8\us,2.4%sy,0.0%ni, 88.9%id,0.8%wa,0.0%hi,0.1%si,0.0%st
Mem:4048972k total,3848576k used,200396k free,134844k buffers
Swap:4194300k total,1788k used,4192512k free,1835360k cached
3. vmstat
vmstat用于显示虚拟内存Linux命令nop,内核线程Linux命令nop,磁盘Linux命令nop,系统进程 , CPU活动等统计信息 。
需要安装sysstat工具 。
[root@dbhost01 ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
rbswpdfreebuffcachesisobiboincs us sy id wa st
201788 202508 135064 18359200032269627612 9510
[root@dbhost01 ~]#
[root@dbhost01 ~]# vmstat 2 5
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
rbswpdfreebuffcachesisobiboincs us sy id wa st
001788 202336 135068 18360000032269727612 9510
001788 202624 135068 1836000002529 4012 668201 9810
001788 202624 135072 1836004005787 4003 668501 9810
101788 202508 135072 1836004005733 4402 735311 9800
001788 202540 135076 1836004003347 4002 667401 9810
4. lsof(list open files)
[root@dbhost01 ~]# lsof | grep 1521
certmonge2348root16rFIFO0,80t015212 pipe
certmonge2348root18rFIFO0,80t015218 pipe
gipcd.bin2754grid109uunix 0xffff8801391521800t036936 socket
5. tcpdump
tcpdump -i eth1
15:24:28.777779 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393080:393596, ack 105, win 148, options [nop,nop,TS val 22996360 ecr 2443327], length 516
15:24:28.777809 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393080:393596, ack 105, win 148, options [nop,nop,TS val 22996360 ecr 2443327], length 516
15:24:28.778976 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393596:393968, ack 105, win 148, options [nop,nop,TS val 22996361 ecr 2443327], length 372
15:24:28.779011 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393596:393968, ack 105, win 148, options [nop,nop,TS val 22996361 ecr 2443327], length 372
15:24:28.779013 IP 192.168.2.82.50990dbhost01.ssh: Flags [.], ack 393968, win 16652, options [nop,nop,TS val 2443327 ecr 22996360], length 0
15:24:28.779481 IP dbhost02-priv.23602dbhost01-priv.24271: UDP, length 556
15:24:28.779585 IP dbhost01-priv.24271dbhost02-priv.23602: UDP, length 80
15:24:28.779909 IP dbhost01-priv.24271dbhost02-priv.23602: UDP, length 80
15:24:28.780584 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393968:394724, ack 105, win 148, options [nop,nop,TS val 22996362 ecr 2443327], length 756
15:24:28.780590 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 393968:394724, ack 105, win 148, options [nop,nop,TS val 22996362 ecr 2443327], length 756
15:24:28.780820 IP dbhost01-priv.24271dbhost02-priv.23602: UDP, length 556
15:24:28.782232 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 394724:395176, ack 105, win 148, options [nop,nop,TS val 22996364 ecr 2443327], length 452
15:24:28.782235 IP dbhost01.ssh192.168.2.82.50990: Flags [P.], seq 394724:395176, ack 105, win 148, options [nop,nop,TS val 22996364 ecr 2443327], length 452
6.netstat
[root@dbhost01 ~]# netstat -a | grep oracle
unix2[ ACC ]STREAMLISTENING31861/var/tmp/.oracle/ora_gipc_sdbhost01gridmyracdb-clusterCRFM_SIPC
unix2[ ACC ]STREAMLISTENING33820/var/tmp/.oracle/sdbhost01DBG_LOGD
unix2[ ACC ]STREAMLISTENING41177/var/tmp/.oracle/sdbhost01DBG_EVMD
unix2[ ACC ]STREAMLISTENING65106/var/tmp/.oracle/sAevm
unix2[ ACC ]STREAMLISTENING65108/var/tmp/.oracle/sSYSTEM.evm.acceptor.auth
7. htop
需要安装
8. iostat
Total DISK READ: 91.48 K/s | Total DISK WRITE: 45.27 K/s
TIDPRIOUSERDISK READDISK WRITESWAPINIOCOMMAND
4071 be/4 oracle30.18 K/s0.00 B/s0.00 %4.69 % ora_lmon_orcl1
4117 be/4 oracle60.36 K/s15.09 K/s0.00 %3.69 % ora_ckpt_orcl1
2989 rt/4 grid965.71 B/s0.00 B/s0.00 %2.13 % ocssd.bin
4099 be/4 oracle0.00 B/s30.18 K/s0.00 %0.07 % ora_ckpt_test
2987 rt/4 grid0.00 B/s482.86 B/s0.00 %0.03 % ocssd.bin
2979 rt/3 root0.00 B/s3.77 K/s0.00 %0.00 % ologgerd -M -d /g01/grid/app/11.2.0/grid/crf/db/dbhost01
2980 rt/3 root0.00 B/s15.09 K/s0.00 %0.00 % ologgerd -M -d /g01/grid/app/11.2.0/grid/crf/db/dbhost01
9. iftop(流量监控工具)
“NOP指令”有何作用?nop指令的作用:
1)就是通过nop指令的填充(nop指令一个字节),使指令按字对齐 , 从而减少取指令时的内存访问次数 。(一般用来内存地址偶数对齐,比如有一条指令,占3字节,这时候使用nop指令,cpu 就可以从第四个字节处读取指令了 。)
2)通过nop指令产生一定的延迟,但是对于快速的CPU来说效果不明显 , 可以使用rep前缀,多延迟几个时钟;--具体应该说是占用了3个时钟脉冲!
3)i/o传输时,也会用一下 nop , 等待缓冲区清空 , 总线恢复;
4)清除由上一个算术逻辑指令设置的flag位;
5)破解:对于原程序中验证部分使用nop来填充 , 使验证失效;
6)有一个朋友说的比较厉害--在航天飞机控制程序中防止程序跳飞!
解释如下:在空间放射性环境下,放射性子粒很容易使内存位元改变(呵呵,有点基因突变的感觉),这样如果改变的是jump,call指令的存贮位置的话,就会导致程序跳转到一个不可以预置的位置,对于关键系统来说的确是灾难性的 。所以就在被调用程序之前填充nop指令 , 这样即使跳转到稍前或者稍后的位置,也不会造成影响 。
计算机科学中,NOP或NOOP(No Operation或No Operation Performed的缩写,意为无操作)是汇编语言的一个指令,一系列编程语句 , 或网络传输协议中的表示不做任何有效操作的命令 。
NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难(en:Hazard (computer architecture)),占据分支指令造成的延迟(delay slot) , 或是作为占位符以供程序的改善(或替代被移除的指令) 。在某些情况中 , NOP指令会产生副作用;例如在摩托罗拉 68000处理器中,NOP操作码会产生流水线同步 。
关于Linux命令nop和linux命令nohub的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息 , 记得收藏关注本站 。
推荐阅读
- 圈29符号电脑怎么打,圈29怎么打出来
- 玩游戏最好的安卓平板推荐,打游戏安卓的平板哪个牌子好
- 手机怎么连接吉利帝豪导航,帝豪车载导航怎样与手机联机
- excel如何替换数据,excel数据怎么替换
- python有参数的函数 python 带参数
- u盘电脑系统怎么删除,u盘系统如何删除
- 模仿动作游戏动作推荐,模仿动作游戏图片
- 快手看点直播怎么关闭,快手哪里关直播
- 录屏程序java源代码 javacv录屏