最近在具体的工程中,在Solaris系统上遇到了信号量设置不当,导致平台通信服务支持的进程数不足的问题。本文主要对信号量一些相关知识进行择要总结,以备忘。
信号量(Semaphore)是E.W.Dijkstra在1965年提出的一种解决进程间通信的方法,它使用一个整型变量来累积唤醒次数,以供以后使用,这个新型的变量称作信号量。一个信号量的值可以为0,表示没有积累下来的唤醒操作;后者为正值,表示有一个或多个被积累下来的唤醒操作。
信号量具备两种操作,之前称为P(wait())和V(signal())。
对一个信号量执行P操作时检查其值是否大于0。若是则将其减去1(即用掉一个保存的唤醒信号)并继续。若值为0,则P操作被阻塞,进程将睡眠。P操作是一个原子操作,保证在操作完成或阻塞之前别的进程均不允许访问该信号量。
V操作递增信号量的值。如果一个或者多个进程在该信号量上睡眠,无法完成先前的P操作,则由系统选择其中一个并允许其完成它的P操作。递增信号量的值和唤醒一个进程同样也是不可分割的。不会有进程因执行V操作而阻塞。
如果信号量只有二进制的0或1,称为二进制信号量。在Linux上,二进制信号量还有一个更广为人知的名字,互斥锁(mutex)。
在Linux操作系统中,信号量的内核限制参数通常在/etc/sysctl.conf配置。
kernel.sem=512 32000 100 256
以上的四个参数分别是SEMMSL,SEMMNS,SEMOPM和SEMMNI。这四个参数可以动态修改,而无需重启操作系统。
SEMMSL是每个信号量组内的信号量的最大值。
SEMMNS是整个系统的信号量的最大值。
SEMOPM是每个semop系统调用的操作最大值。
SEMMNI是信号量组的最大值。
我们可以通过ipcs -l
命令来显示系统信号量的限制的具体值。
# ipcs -l
------ Semaphore Limits --------
max number of arrays = 256
max semaphores per array = 512
max semaphores system wide = 32000
max ops per semop call = 100
semaphore max value = 32767
在Solaris操作系统中,信号量的内核限制参数在/etc/system中配置。
set semsys:seminfo_semmni=100
set semsys:seminfo_semmsl=256
set semsys:seminfo_semmns=1024
set semsys:seminfo_semopm=100
set semsys:seminfo_semvmx=32767
其中参数的含义和Linux系统基本一致。
这里需要特别提到一个参数,这个参数从Solaris 10开始已经被取消了。但是在一些使用之前Solaris系统的工程中,需要格外注意。引子中提到的问题也与这个参数有关。这个参数就是SEMMNU。
set semsys:seminfo_semmnu = 2048 (removed in Solaris 10 and 11)
SEMMNU参数的含义是整个系统的信号量撤销结构的最大值,通常会将其设置的大小和SEMMNS一致。有这样一个参考公式:
SEMMNS = SEMMNU = (SEMMIN * SEMMSL)
而在Sloaris 8上的SEMMNU默认值30,在使用信号量作为进程间通信基础的场景中,这个设置值太低了。
信号量作为IPC的方式之一,通常使用IPC的操作命令 ipcs
和 ipcrm
对信号量进行查看和操作。
ipcs
用于输出IPC相关内容的信息,可以使用 -s
参数来查看系统的信号量信息。
# ipcs -s
------ Semaphore Arrays --------
key semid owner perms nsems
0x4e00645c 32769 test 666 1
0x2b6d5d5e 65538 test 666 1
0xd631c667 98307 test 666 1
0xc5b35482 131076 test 666 1
0x71b6a0a7 163845 test 666 256
0x4073f280 196614 test 666 1
0xf4e14d7c 229383 test 666 1
0xa6da2602 262152 test 666 1
0x387e3d95 491532 test 644 3
0xc8ff5d03 524301 test 644 3
0x3324c83c 557070 test 644 3
0xe2a5046d 589839 test 644 3
0x79e72ebd 622608 test 644 3
0x880ddd3a 655377 test 644 3
0x37cf505a 688146 test 644 3
0xd70924a5 720915 test 644 3
0x8be73547 753684 test 644 3
ipcrm
用于删除IPC相关的共享资源(如消息队列、信号量或共享内存),可以通过 -s
或 -S
参数来操作信号量。
# ipcrm -s semid
# ipcrm -S semkey
待补充