3、信号量是操作
  semctl函数对一个信号量执行各种控制操作。
  #include <sys/sem.h>
  int semctl (int semid, int semnum, int cmd, /*可选参数*/ ) ;
  第四个参数是可选的,取决于第三个参数cmd。
  参数semnum指定信号集中的哪个信号(操作对象)
  参数cmd指定以下10种命令中的一种,在semid指定的信号量集合上执行此命令。
  IPC_STAT   读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
  IPC_SET     设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
  IPC_RMID  将信号量集从内存中删除。
  GETALL      用于读取信号量集中的所有信号量的值。
  GETNCNT  返回正在等待资源的进程数目。
  GETPID      返回后一个执行semop操作的进程的PID。
  GETVAL      返回信号量集中的一个单个的信号量的值。
  GETZCNT   返回这在等待完全空闲的资源的进程数目。
  SETALL       设置信号量集中的所有的信号量的值。
  SETVAL      设置信号量集中的一个单独的信号量的值。
  六 信号量值的初始化
  semget并不初始化各个信号量的值,这个初始化必须通过以SETVAL命令(设置集合中的一个值)或SETALL命令(设置集合中的所有值) 调用semctl来完成。
  SystemV信号量的设计中,创建一个信号量集并将它初始化需两次函数调用是一个致命的缺陷。一个不完备的解决方案是:在调用semget时指定IPC_CREAT | IPC_EXCL标志,这样只有一个进程(首先调用semget的那个进程)创建所需信号量,该进程随后初始化该信号量。
  七 例子
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
static int sem_id = 0;
static int set_semvalue();
static void del_semvalue();
static int semaphore_p();
static int semaphore_v();
int main(int argc, char *argv[])
{
char message = 'X';
int i = 0;
/* 创建信号量 */
sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
if(argc > 1)
{
/* 程序第一次被调用,初始化信号量 */
if(!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore ");
exit(EXIT_FAILURE);
}
/* 设置要输出到屏幕中的信息,即其参数的第一个字符 */
message = argv[1][0];
sleep(2);
}
for(i = 0; i < 10; ++i)
{
/* 进入临界区 */
if(!semaphore_p())
{
exit(EXIT_FAILURE);
}
/* 向屏幕中输出数据 */
printf("%c", message);
/* 清理缓冲区,然后休眠随机时间 */
fflush(stdout);
sleep(rand() % 3);
/* 离开临界区前再一次向屏幕输出数据 */
printf("%c", message);
fflush(stdout);
/* 离开临界区,休眠随机时间后继续循环 */
if(!semaphore_v())
{
exit(EXIT_FAILURE);
}
sleep(rand() % 2);
}
sleep(10);
printf(" %d - finished ", getpid());
if(argc > 1)
{
/* 如果程序是第一次被调用,则在退出前删除信号量 */
sleep(3);
del_semvalue();
}
exit(EXIT_SUCCESS);
}
static int set_semvalue()
{
/* 用于初始化信号量,在使用信号量前必须这样做 */
union semun sem_union;
sem_union.val = 1;
if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
return 0;
}
return 1;
}
static void del_semvalue()
{
/* 删除信号量 */
union semun sem_union;
if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
fprintf(stderr, "Failed to delete semaphore ");
}
}
static int semaphore_p()
{
/* 对信号量做减1操作,即等待P(sv)*/
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed ");
return 0;
}
return 1;
}
static int semaphore_v()
{
/* 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)*/
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed ");
return 0;
}
return 1;
}
  八 信号量集合的例子
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAX_SEMAPHORE 10
#define FILE_NAME "test2.c"
union semun{
int val ;
struct semid_ds *buf ;
unsigned short *array ;
struct seminfo *_buf ;
}arg;
struct semid_ds sembuf;
int main()
{
key_t key ;
int semid ,ret,i;
unsigned short buf[MAX_SEMAPHORE] ;
struct sembuf sb[MAX_SEMAPHORE] ;
pid_t pid ;
pid = fork() ;
if(pid < 0)
{
/* Create process Error! */
fprintf(stderr,"Create Process Error!:%s ",strerror(errno));
exit(1) ;
}
if(pid > 0)
{
/* in parent process !*/
key = ftok(FILE_NAME,'a') ;
if(key == -1)
{
/* in parent process*/
fprintf(stderr,"Error in ftok:%s! ",strerror(errno));
exit(1) ;
}
semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666); //创建信号量集合
if(semid == -1)
{
fprintf(stderr,"Error in semget:%s ",strerror(errno));
exit(1) ;
}
printf("Semaphore have been initialed successfully in parent process,ID is :%d ",semid);
sleep(2) ;
printf("parent wake up.... ");
/* 父进程在子进程得到semaphore的时候请求semaphore,此时父进程将阻塞直至子进程释放掉semaphore*/
/* 此时父进程的阻塞是因为semaphore 1 不能申请,因而导致的进程阻塞*/
for(i=0;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = -1 ; /*表示申请semaphore*/
sb[i].sem_flg = 0 ;
}
printf("parent is asking for resource... ");
ret = semop(semid , sb ,10); //p()
if(ret == 0)
{
printf("parent got the resource! ");
}
/* 父进程等待子进程退出 */
waitpid(pid,NULL,0);
printf("parent exiting .. ");
exit(0) ;
}
else
{
/* in child process! */
key = ftok(FILE_NAME,'a') ;
if(key == -1)
{
/* in child process*/
fprintf(stderr,"Error in ftok:%s! ",strerror(errno));
exit(1) ;
}
semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666);
if(semid == -1)
{
fprintf(stderr,"Error in semget:%s ",strerror(errno));
exit(1) ;
}
printf("Semaphore have been initialed successfully in child process,ID is:%d ",semid);
for(i=0;i<MAX_SEMAPHORE;++i)
{
/* Initial semaphore */
buf[i] = i + 1;
}
arg.array = buf;
ret = semctl(semid , 0, SETALL,arg);
if(ret == -1)
{
fprintf(stderr,"Error in semctl in child:%s! ",strerror(errno));
exit(1) ;
}
printf("In child , Semaphore Initailed! ");
/* 子进程在初始化了semaphore之后,申请获得semaphore*/
for(i=0;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = -1 ;
sb[i].sem_flg = 0 ;
}
ret = semop(semid , sb , 10);//信号量0被阻塞
if( ret == -1 )
{
fprintf(stderr,"子进程申请semaphore失败:%s ",strerror(errno));
exit(1) ;
}
printf("child got semaphore,and start to sleep 3 seconds! ");
sleep(3) ;
printf("child wake up . ");
for(i=0;i < MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = +1 ;
sb[i].sem_flg = 0 ;
}
printf("child start to release the resource... ");
ret = semop(semid, sb ,10) ;
if(ret == -1)
{
fprintf(stderr,"子进程释放semaphore失败:%s ",strerror(errno));
exit(1) ;
}
ret = semctl(semid ,0 ,IPC_RMID);
if(ret == -1)
{
fprintf(stderr,"semaphore删除失败:%s! ",strerror(errno));
exit(1) ;
}
printf("child exiting successfully! ");
exit(0) ;
}
return 0;
}
  【信号量的意图在于进程间同步,互斥锁和条件变量的意图则在于线程间同步。但是信号量也可用于线程间,互斥锁和条件变量也可用于进程间。我们应该使用适合具体应用的那组原语。】