首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux 进程间通讯-信号量

2013-01-18 
linux 进程间通讯--信号量PV的定义 P就是请求资源,V就是释放资源P(sv)如果sv大于0,减小sv。如果sv为0,挂起

linux 进程间通讯--信号量

PV的定义 P就是请求资源,V就是释放资源

P(sv)    如果sv大于0,减小sv。如果sv为0,挂起这个进程的执行。
V(sv)    如果有进程被挂起等待sv,使其恢复执行。如果没有进行被挂起等待sv,增加sv。

P表示通过的意思,V表示释放的意思

System V机制

一.头文件

#include <sys/sem.h>

二.结构体

struct sembuf {unsigned short   sem_num; /* semaphore index in array *///处理的信号量个数short sem_op; /* semaphore operation *///要执行的操作类型short sem_flg; /* operation flags *///操作标识};
union semun {    int val;    struct semid_ds *buf;    unsigned short  *array;} arg;

三.API函数

1.获取key_t值

key_t ftok(const char *path, int id);

2.获取设置信号量

int semget(key_t key, int nsems, int semflg);

参数:信号量集键值,信号量格式,信号量标志

返回值:成功返回semid,,错误返回-1,

错误号errno:

    EACCES 权限过低

    EEXIST:id存在,但((semflg &IPC_CREAT) &&(semflg &IPC_EXCL))=0

    EINVAL:nsems参数不对

    ENOENT:id不存在且semflg &IPC_CREAT=0

    ENOSPC:信号量数超过系统限制

当key为IPC_PRIVATE或者当不存在key指定的id时且semflg &IPC_CREAT=0 会创建信号量

 

3.信号量控制

int semctl(int semid, int semnum, int cmd, ...);

参数:信号量集键值,信号量遍号,命令,可选参数(union semun)

返回值:成功返回整数,是吧返回-1

命令:

GETVAL:返回信号量集中的一个单个的信号量的值

SETVAL:设置信号量集中的一个单独的信号量的值

GETPID:返回最后一个执行semop操作的进程的PID

GETNCNT:用于读取信号量集中的所有信号量的值

GETZCNT:返回这在等待完全空闲的资源的进程数目

GETALL:用于读取信号量集中的所有信号量的值

SETVAL:设置信号量集中的一个单独的信号量的值

IPC_STAT:读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中

IPC_SET:设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数

IPC_RMID:将信号量集从内存中删除

4.信号量操作

int semop(int semid, struct sembuf *sops, size_t nsops); 

参数:信号量集键值,sembuf结构体,操作标志

返回值:成功返回0,失败返回-1

sop->sem_ops的说明:

值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;

值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;

值为0,则操作将暂时阻塞,直到信号的值变为0

四.例子

 1.

#include <sys/types.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/stat.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <pwd.h>#include <fcntl.h>#include <limits.h>int main(int argc,char **argv){key_t semkey;int semid, pfd, fv;struct sembuf sbuf;char *lgn;char filename[PATH_MAX+1];struct stat outstat;struct passwd *pw;/* Get unique key for semaphore. */if ((semkey = ftok("/tmp", 'b')) == (key_t) -1) {perror("IPC error: ftok"); exit(1);}/* Get semaphore ID associated with this key. */if ((semid = semget(semkey, 0, 0)) == -1) {/* Semaphore does not exist - Create. */if ((semid = semget(semkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) != -1){    /* Initialize the semaphore. */    sbuf.sem_num = 0;    sbuf.sem_op = 2;  /* This is the number of runswithout queuing. */    sbuf.sem_flg = 0;    if (semop(semid, &sbuf, 1) == -1) {        perror("IPC error: semop"); exit(1);    }}else if (errno == EEXIST) {    if ((semid = semget(semkey, 0, 0)) == -1) {        perror("IPC error 1: semget"); exit(1);    }}else {    perror("IPC error 2: semget"); exit(1);}}}

2.网上找到的例子

#include <sys/types.h>#include <sys/shm.h>#include <sys/sem.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <signal.h> #define SHMDATASIZE 1000#define BUFFERSIZE (SHMDATASIZE - sizeof ( int ))#define SN_EMPTY 0#define SN_FULL 1#define TRUE 1int deleteSemid = 0;// 必须自己定义一个 union, 否则编译不过union semun{    int val ;    struct semid_ds * buf ;    unsigned short int * array ;    struct seminfo * __buf ;};void server ();void client ( int shmid);void delete ();void sigdelete ( int signum);void locksem ( int semid, int semnum);void unlocksem ( int semid, int semnum);//void waitzero(int semid, int semnum);void clientwrite ( int shmid, int semid, char *buffer); int safesemget (key_t key, int nsems, int semflg);int safesemctl ( int semid, int semnum, int cmd, union semun arg);int safesemop ( int semid, struct sembuf *sops, unsigned nsops);int safeshmget (key_t key, int size, int shmflg);void * safeshmat ( int shmid, const void *shmaddr, int shmflg);int safeshmctl ( int shmid, int cmd, struct shmid_ds *buf); int main ( int argc, char *argv[]){    if (argc < 2)    { // 一个参数启动 server       server();    }    else    { // 多个参数启动 client       client( atoi (argv[1])); //atoi 把字符串转为整形数    }    return 0;}  void server (){    union semun sunion; // 与 semctl 中的 cmd 参数有关    int semid, shmid;    void *shmdata;    char *buffer;    semid = safesemget(IPC_PRIVATE, 2, SHM_R | SHM_W); // 创建一个信号集    deleteSemid = semid;    atexit (&delete); // 注册终止函数    signal (SIGINT, &sigdelete); // 设置某一信号的对应动作 , 程序终止 (interrupt) 信号 , 在用户键入 INTR 字符 ( 通常是 Ctrl-C) 时发出    sunion. val = 1; // 将一个二元信号量初始化为 1    safesemctl(semid, SN_EMPTY, SETVAL, sunion); //SETVAL 设置信号量集中的一个单独的信号量的值    sunion. val = 0; // 将一个二元信号量赋值为 0    safesemctl(semid, SN_FULL, SETVAL, sunion);    shmid = safeshmget(IPC_PRIVATE, SHMDATASIZE, IPC_CREAT | SHM_R | SHM_W); // 创建共享内存    shmdata = safeshmat(shmid, 0, 0); // 将该共享内存映射进进程的虚存空间    safeshmctl(shmid, IPC_RMID, NULL); // 将该共享内存标志为已销毁的,这样在使用完毕后,将被自动销毁    *( int *) shmdata = semid; // 将信号量的标识符写入共享内存,以通知其它的进程    buffer = shmdata + sizeof ( int ); //buf 数据的起始地址 , 因为第一个地址装载了 semid    printf ( "server is running with SHM id ** %d **\n" , shmid);    while (TRUE)    {       printf ( "waiting until full... " );       fflush (stdout);       locksem(semid, SN_FULL); // 获得共享资源       printf ( "done. \n" );       printf ( "message received: %s.\n" , buffer);       unlocksem(semid, SN_EMPTY);    }} void client ( int shmid){    int semid;    void *shmdata;    char *buffer;    shmdata = safeshmat(shmid, 0, 0); // 将该共享内存映射进进程的虚存空间 , 这时共享内存的第一个数据是之前 sercer 写入的    semid = *( int *) shmdata; // 获得 server 创建的共享内存    buffer = shmdata + sizeof ( int ); //buf 数据的起始地址 , 因为第一个地址装载了 semid    printf ( "client operational: shm id is %d,sem id is %d\n" , shmid, semid);    while (TRUE)    {       char input[3];       printf ( "\n menu \n1.Send a message\n" );       printf ( "2.Exit\n" );       fgets (input, sizeof (input), stdin);       switch (input[0])       {       case '1' :           clientwrite(shmid, semid, buffer);           break ;       case '2' :           exit (0);           break ;       }    }}  int safesemget (key_t key, int nsems, int semflg){    int retval;    if ((retval = semget(key, nsems, semflg)) == -1)    {       printf ( "semget error: %s. \n" , strerror(errno));       exit (254);    }    return retval;}  void sigdelete ( int signum){    exit (0);}  int safesemctl ( int semid, int semnum, int cmd, union semun arg){    int retval;    if ((retval = semctl(semid, semnum, cmd, arg)) == -1)    {       printf ( "semctl error: %s. \n" , strerror(errno));       exit (254);    }    return retval;}  int safeshmget (key_t key, int size, int shmflg){    int retval;    if ((retval = shmget(key, size, shmflg)) == -1)    {       printf ( "shmget error: %s. \n" , strerror(errno));       exit (254);    }    return retval;}  void * safeshmat ( int shmid, const void *shmaddr, int shmflg){    void * retval;    if ((retval = shmat(shmid, shmaddr, shmflg)) == ( void *) -1)    {       printf ( "shmat error: %s. \n" , strerror(errno));       exit (254);    }    return retval;}  int safeshmctl ( int shmid, int cmd, struct shmid_ds *buf){    int retval;    if ((retval = shmctl(shmid, cmd, buf)) == -1)    {       printf ( "shmctl error: %s. \n" , strerror(errno));       exit (254);    }    return retval;}  void locksem ( int semid, int semnum){    struct sembuf sb; // 指定调用 semop 函数所做操作    sb. sem_num = semnum; // 指定要操作的信号量    sb. sem_op = -1; // 要执行的操作 ,<0 表示进程希望使用资源    sb. sem_flg = SEM_UNDO; // 标志    safesemop(semid, &sb, 1);} void unlocksem ( int semid, int semnum){    struct sembuf sb; // 指定调用 semop 函数所做操作    sb. sem_num = semnum; // 指定要操作的信号量    sb. sem_op = 1; // 要执行的操作 ,>0 表示對進程的资源使用完畢 , 交回该资源    sb. sem_flg = SEM_UNDO; // 标志    safesemop(semid, &sb, 1);}  int safesemop ( int semid, struct sembuf *sops, unsigned nsops){    int retval;    if ((retval = semop(semid, sops, nsops)) == -1)    {       printf ( "semop error: %s. \n" , strerror(errno));       exit (254);    }    return retval;} void clientwrite ( int shmid, int semid, char *buffer){    printf ( "waiting until empty..." );    fflush (stdout);    locksem(semid, SN_EMPTY); // 这个过程是在等待共享内存资源    printf ( "done.\n" );    printf ( "enter message: " );    fgets (buffer, BUFFERSIZE, stdin);    unlocksem(semid, SN_FULL);} void delete (){    printf ( "\n master exiting; deleting semaphore %d. \n" , deleteSemid);    if ((semctl(deleteSemid, 0, IPC_RMID, 0)) == -1) //IPC_RMID 删除该信号量       printf ( "error releasing semaphore. \n" );}

例子使用说明:

运行服务端:./app 不带参数

server is running with SHM id ** 8257564 **
waiting until full... 1
运行客户端./APP 8257564

 menu
1.Send a message
2.Exit
选择1发送信息

waiting until empty...done.
enter message:

输入信息并按回车

选择2退出客户端

 

^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^_^

Posix机制

一.头文件

#include <semaphore.h>

二.结构体

三.API函数

无名信号量:

1.初始化无名信号量

int sem_init(sem_t *sem, int pshared, unsigned value);

参数:

    sem: 信号量标识ID

    pshared:为0表示同一进程内的线程共享,非0值则为进程间共享

    value:
2.销毁无名信号量

int sem_destroy(sem_t *sem);

    sem: 信号量标识ID

 

有名信号量:

3.初始化并使用有名信号量

sem_t *sem_open(const char *name, int oflag, /* mode_t mode, unsigned int *value */);

参数:

    name:信号量外部别名

    oflag:标志

    mode:权限(可选参数)

    value:信号量初始值

4.关闭有名信号量

int sem_close(sem_t *sem);

参数:

    sem: 信号量标识ID

5.移除有名信号量

int sem_unlink(const char *name);

参数:

    name:信号量外部别名

V操作

6.释放信号量

int sem_post(sem_t *sem);

参数:

    sem: 信号量标识ID

P操作

7.申请信号量

int sem_wait(sem_t *sem);

参数:

    sem: 信号量标识ID

 

8.尝试申请信号量

int sem_trywait(sem_t *sem);

参数:

    sem: 信号量标识ID

四.例子

#include <unistd.h> #include <pthread.h> #include <stdio.h> #include <errno.h> #include <semaphore.h>   sem_t add;                   sem_t sub;       void* thread0(void *param)             {     while(1){         sem_wait( &add);while(1){char input[3];fgets(input,sizeof(input),stdin);if(input[0]==']'){(*(int*)param) += 1;continue;}else{break;}}        printf("Thread0: %d\n", *(int*)param); sem_post( &sub);                            sleep(1);     }     return NULL; }   void* thread1(void *param) {     while(1){         sem_wait( &sub); while(1){char input[2];fgets(input,sizeof(input),stdin);if(input[0]=='['){(*(int*)param) -= 1;continue;}else{break; }}        printf("Thread1: %d\n", *(int*)param);         sem_post(&add);                sleep(1);     }     return NULL; }   int main() {     int sum = 0;     int i;       sem_init(&add, 0, 100);     sem_init(&sub, 0, sum);     pthread_t ths[2];     pthread_create(&ths[0], NULL,  thread0, (void*)&sum);     pthread_create(&ths[1], NULL,  thread1, (void*)&sum);     for(i = 0; i < 2; ++ i){         pthread_join(ths[i], NULL);     } } 





 

 

热点排行