Linux互斥与同步应用(五):system V信号量的互斥与同步

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途】

system V信号量操作类似于posix信号量,但system V信号量的操作要复杂得多,posix信号量使用步骤为sem_init(sem_open)-->sem_wait(sem_post) --> sem_close详见上一节,system V使用不同的函数。

1. 创建和打开信号量函数:semget()。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
       int semget(key_t key, int nsems, int semflg);

key为ftok返回值或IPC_PRIVATE;

nsems为指定信号量集合中信号量的数量,一旦创建就不能更改,需要大于0,如果等于0则方位一个已存在的集合。

semflg为读写权限值组合。IPC_CREAT(创建新的信号量集合)或IPC_CREAT|IPC_EXCL(当将要创建的信号量集合已经存在时,再试图创建将返回EEXIST)。其实IPC_CREAT和IPC_EXCL的组合和open函数的O_CREAT和O_EXCL组合类似。

2. 对象信号集合进行操作函数:semctl()。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
       int semctl(int semid, int semnum, int cmd, ...);

semid为信号量标识,函数semget的返回值。

semnum为信号在信号集合中的序号。

cmd为操作的命令:

GETVAL -
返回指定信号量当前值;

SETVAL -
设置指定信号量的值;

IPC_RMIN - 删除信号量集合。

其余命令详见man手册。

初始化一个system V信号量如下:

int sln_seminit(const char *filename, int initval)
{
    int     semid;
    key_t   keyid;
    keyid = ftok(filename, 0);
    if (keyid < 0) {
        fprintf(stderr, "ftok: %s\n", strerror(errno));
        return -1;
    }
    semid = semget(keyid, 1, IPC_CREAT | IPC_EXCL);
    if (semid >= 0) { // 创建成功,然后修改信号量的初始值为initval
        printf("=== new sem create! ===\n");
        if (semctl(semid, 0, SETVAL, initval) < 0) {
            printf("semctl: %s\n", strerror(errno));
            return -1;
        }
    } else if (EEXIST == errno) {  //信号量存在,则打开,再次修改信号量的初始值。
        printf("=== open a exist sem! ===\n");
        semid = semget(keyid, 0, 0);
        if (semid < 0) {
            printf("[%d] - semget: %s\n", __LINE__, strerror(errno));
            return -1;
        }
        if (semctl(semid, 0, SETVAL, initval) < 0) {
            printf("semctl: %s\n", strerror(errno));
            return -1;
        }
    } else { //create failed, other reason
        printf("[%d] - semget: %s,  semid: %d\n", __LINE__, strerror(errno), semid);
    }
    return semid;
}

3.信号量PV操作函数:semop(),semtimedop()函数。

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

       int semop(int semid, struct sembuf *sops, unsigned nsops);
       int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);

semid为信号量标识,函数semget的返回值;

sops指向信号量操作结构数组指针;

nsops为指向数组中sembuf结构体个数。

struct sembuf {
    short sem_num;    // 要操作的信号量在信号量集里的编号,
    short sem_op;     // 信号量操作
    short sem_flg;     // 操作表示符
};

若sem_op 是正数,其值就加到semval上,即释放信号量控制的资源

若sem_op 是0,那么调用者希望等到semval变为0,如果semval是0就返回;

若sem_op 是负数,那么调用者希望等待semval变为大于或等于sem_op的绝对值

P、V操作的实现为:

void sln_sem_wait(int semid)
{
    struct sembuf   sb;
    memset(&sb, 0, sizeof(struct sembuf));
    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;
    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}
void sln_sem_post(int semid)
{
    struct sembuf   sb;
    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = 1;
    sb.sem_flg = 0;
    //sb.sem_flg = SEM_UNDO;
    if (semop(semid, &sb, 1) < 0) {
        printf("shm unlock error! semop: %s\n", strerror(errno));
    }
}

示例代码:

服务进程:

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>  //ftok()
#include <string.h>
#include <sys/sem.h>
#include <sys/shm.h> //shmat()
#include <unistd.h> //access()
#include <stdlib.h> // exit()
#include <signal.h> //signal()

#include "shmipc.h"

int         sem_clt2ser, sem_ser2clt, sem_mutex_id;

int sln_shm_get(const char *filename, void **mem, int mem_len)
{
    int     shmid;
    key_t   shm_key;

    shm_key = ftok(filename, 0);
    if (shm_key < 0) {
        fprintf(stderr, "ftok: %s\n", strerror(errno));
        return -1;
    }

    shmid = shmget(shm_key, mem_len, IPC_CREAT);
    if (shmid < 0) {
        printf("shmget: %s\n", strerror(errno));
        return -1;
    }

    *mem = (void *)shmat(shmid, NULL, 0);
    if ((void *)-1 == *mem) {
        printf("shmat: %s\n", strerror(errno));
        return -1;
    }

//    semget(shm_key, 1, IPC_CREAT);

    return shmid;
}

void sln_sem_wait_timeout(int semid)
{
    struct sembuf   sb;
    struct timespec tp;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    tp.tv_sec = time(NULL) + SEM_TIMEOUT_SEC;
    tp.tv_nsec = 0;

    if (semtimedop(semid, &sb, 1, &tp) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_sem_wait(int semid)
{
    struct sembuf   sb;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_sem_post(int semid)
{
    struct sembuf   sb;

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = 1;
    sb.sem_flg = 0;
    //sb.sem_flg = SEM_UNDO;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm unlock error! semop: %s\n", strerror(errno));
    }
}

void sln_shm_lock(int semid)
{
    struct sembuf   sb;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    //sb.sem_flg = 0;
    sb.sem_flg = SEM_UNDO;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_shm_unlock(int semid)
{
    struct sembuf   sb;

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = 1;
    //sb.sem_flg = 0;
    sb.sem_flg = SEM_UNDO;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm unlock error! semop: %s\n", strerror(errno));
    }
}

int sln_seminit(const char *filename, int initval)
{
    int     semid;
    key_t   keyid;

    keyid = ftok(filename, 0);
    if (keyid < 0) {
        fprintf(stderr, "ftok: %s\n", strerror(errno));
        return -1;
    }

    semid = semget(keyid, 1, IPC_CREAT | IPC_EXCL);

    if (semid >= 0) { // create success
        printf("=== new sem create! ===\n");
        if (semctl(semid, 0, SETVAL, initval) < 0) {
            printf("semctl: %s\n", strerror(errno));
            return -1;
        }
    } else if (EEXIST == errno) {  //exist, create failed!
        printf("=== open a exist sem! ===\n");
        semid = semget(keyid, 0, 0);
        if (semid < 0) {
            printf("[%d] - semget: %s\n", __LINE__, strerror(errno));
            return -1;
        }
        if (semctl(semid, 0, SETVAL, initval) < 0) {
            printf("semctl: %s\n", strerror(errno));
            return -1;
        }
    } else { //create failed, other reason
        printf("[%d] - semget: %s,  semid: %d\n", __LINE__, strerror(errno), semid);
    }

    return semid;
}

static void sln_create_not_exist_file(const char *filename)
{
    FILE        *fp = NULL;

    if (access(filename, F_OK) < 0) {
        fp = fopen(filename, "w+");
        if (NULL == fp) {
            fprintf(stderr, "fopen <%s> failed!\n", filename);
            return;
        }
        fclose(fp);
    }
}

static void sigint_func(int sig)
{
    if (semctl(sem_clt2ser, 0, IPC_RMID) < 0) {
        printf("semctl: %s\n", strerror(errno));
    }
    if (semctl(sem_ser2clt, 0, IPC_RMID) < 0) {
        printf("semctl: %s\n", strerror(errno));
    }
    if (semctl(sem_mutex_id, 0, IPC_RMID) < 0) {
        printf("semctl: %s\n", strerror(errno));
    }
    exit(0);
}

int main(int argc, const char *argv[])
{
    char        *str = NULL;

    sln_create_not_exist_file(SLN_SEM_SERWAIT_FILEPATH);
    sln_create_not_exist_file(SLN_SEM_CLTWAIT_FILEPATH);
    sln_create_not_exist_file(SLN_SEM_MUTEX_FILEPATH);

    sem_clt2ser = sln_seminit(SLN_SEM_SERWAIT_FILEPATH, 0);
    if (sem_clt2ser < 0) {
        printf("sync sem init failed!\n");
        return -1;
    }

    sem_ser2clt = sln_seminit(SLN_SEM_CLTWAIT_FILEPATH, 0);
    if (sem_clt2ser < 0) {
        printf("sync sem init failed!\n");
        return -1;
    }

    sem_mutex_id = sln_seminit(SLN_SEM_MUTEX_FILEPATH, 1);
    if (sem_mutex_id < 0) {
        printf("mutex sem init failed!\n");
        return -1;
    }

    //signal(SIGINT, sigint_func);

    for (;;) {
        printf("--------start wait!---semval: %d------\n", semctl(sem_clt2ser, 0, GETVAL, 0));
        sln_sem_wait(sem_clt2ser);

        printf("=====stat handle!========\n");
        sln_shm_lock(sem_mutex_id);
        sln_shm_get(SLN_SEM_MUTEX_FILEPATH, (void **)&str, 32);
        sleep(6);
        printf("str: %s\n", str);
        if (shmdt(str) < 0) {
            printf("shmdt: %s\n", strerror(errno));
        }
        sln_shm_unlock(sem_mutex_id);
        printf("=====handle ok!========\n");

        sln_sem_post(sem_ser2clt);
    }

    return 0;
}

客户进程代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>  //ftok()
#include <sys/sem.h>

#include "shmipc.h"

int sln_shm_get(const char *filename, void **mem, int mem_len)
{
    int     shmid;
    key_t   shm_key;

    shm_key = ftok(filename, 0);
    if (shm_key < 0) {
        fprintf(stderr, "ftok: %s\n", strerror(errno));
        return -1;
    }

    shmid = shmget(shm_key, mem_len, IPC_CREAT);
    if (shmid < 0) {
        printf("shmget: %s\n", strerror(errno));
        return -1;
    }

    *mem = (void *)shmat(shmid, NULL, 0);
    if ((void *)-1 == *mem) {
        printf("shmat: %s\n", strerror(errno));
        return -1;
    }

    return shmid;
}

void sln_sem_wait_timeout(int semid)
{
    struct sembuf   sb;
    struct timespec tp;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    tp.tv_sec = time(NULL) + SEM_TIMEOUT_SEC;
    tp.tv_nsec = 0;

    /*
    if (semtimedop(semid, &sb, 1, &tp) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
    */
    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_sem_wait(int semid)
{
    struct sembuf   sb;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_sem_post(int semid)
{
    struct sembuf   sb;

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = 1;
    sb.sem_flg = 0;
    //sb.sem_flg = SEM_UNDO;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm unlock error! semop: %s\n", strerror(errno));
    }
}

void sln_shm_lock(int semid)
{
    struct sembuf   sb;

    memset(&sb, 0, sizeof(struct sembuf));

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm lock error! semop: %s\n", strerror(errno));
    }
}

void sln_shm_unlock(int semid)
{
    struct sembuf   sb;

    sb.sem_num = SLN_SEM_NUM;
    sb.sem_op = 1;
    sb.sem_flg = 0;

    if (semop(semid, &sb, 1) < 0) {
        printf("shm unlock error! semop: %s\n", strerror(errno));
    }
}

int sln_semget(const char *filename)
{
    int     semid;
    key_t   keyid;

    keyid = ftok(filename, 0);
    if (keyid < 0) {
        fprintf(stderr, "ftok: %s\n", strerror(errno));
        return -1;
    }

    return semget(keyid, 0, 0);
}

int main(int argc, const char *argv[])
{
    char        *str = NULL;
    int         sem_clt2ser, sem_ser2clt, sem_mutex_id;

    sem_clt2ser = sln_semget(SLN_SEM_SERWAIT_FILEPATH);
    if (sem_clt2ser < 0) {
        printf("semget: %s\n", strerror(errno));
        return -1;
    }

    sem_ser2clt = sln_semget(SLN_SEM_CLTWAIT_FILEPATH);
    if (sem_ser2clt < 0) {
        printf("semget: %s\n", strerror(errno));
        return -1;
    }

    sem_mutex_id = sln_semget(SLN_SEM_MUTEX_FILEPATH);
    if (sem_mutex_id < 0) {
        printf("mutex sem failed!\n");
        return -1;
    }

    printf("--------cli wait!-sem_mutex_id: %d--------\n", sem_mutex_id);
    sln_shm_lock(sem_mutex_id);
    printf("--------cli wait ok !---------\n");

    sln_shm_get(SLN_SEM_MUTEX_FILEPATH, (void **)&str, 32);
    strcpy(str, argv[1]);

    sln_shm_unlock(sem_mutex_id);

    sln_sem_post(sem_clt2ser);
    sln_sem_wait(sem_ser2clt);
    printf("=========set: %s=========\n", str);

    return 0;
}

源码下载:

点击打开链接

时间: 2024-10-13 23:31:51

Linux互斥与同步应用(五):system V信号量的互斥与同步的相关文章

linux进程通信之SYSTEM V信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有.信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒. 一.信号量的分类: 在学习信号量之前,我们必须先知道--Linux提供两种信号量: (1) 内核信号量,由内核控制路径使用. (2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量. POSIX信号量又分为有名信号量和无名信号量.有名信号量,其值保存在文件

Linux系统编程——进程同步与互斥:System V 信号量

信号量概述 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问. 编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞.PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1. 在实际应用中两个进程间通信可能会使用多个信号量,因此 System V 的信号量以集合的概念来管理,具体操作和Posix 信号量大同小异,详情请点此链接:http://blog.cs

Linux IPC实践(11) --System V信号量(1)

信号量API #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); int semctl(int semid, int semnum, int cmd, ...); int semop(int semid, struct sembuf *sops, unsigned nsops); semget int

System V信号量(1)

原创整理不易,转载请注明出处:使用Memcached.Spring AOP构建数据库前端缓存框架 代码下载地址:http://www.zuidaima.com/share/1781569917635584.htm 数 据库访问可能是很多网站的瓶颈.动不动就连接池耗尽.内存溢出等.前面已经讲到如果我们的网站是一个分布式的大型站点,那么使用memcached实现数 据库的前端缓存是个很不错的选择:但如果网站本身足够小只有一个服务器,甚至是vps的那种,不推荐使用memcached,使用Hiberna

system v信号量的深入剖析

最近看了linux的SYSTEM V信号量的部分,同时对于信号量的数据结构以及系统调用函数的具体实现进行了分析,现将这部分资料进行一个整理,以便于自己理清思路,同时便于以后的查看,若里面有写的不当之处,还望大家指教. 需要说明的是本报告是基于linux-2.6.11版本 第一部分  信号量的数据结构 1.信号量的分类: (1)内核级信号量,及内核函数采用的信号量. (2)用户级信号量(只是用户态使用)可分为POSIX信号量和SYSTEM V信号量 2.本文只对system v信号量进行分析 为了

System V 信号量使用相关函数

System V 信号量 在提到Posix 信号量时,指的是二值信号量或计数信号量,而System V信号量指的是入了计数信号量集 二值信号量:其值为0或1,类似于互斥锁,资源被锁住时为0,资源可用为1计数信号量:其值在0和某个限制值之间的信号量,信号量的值就是可用资源数计数信号量集:一个或多个信号量构成一个集合,集合中每个元素都是计数信号量(每个集合的信号量数存在一个限制) semid_ds结构: 内核为每个信号量集维护的信息结构 #include <sys/sem.h> struct se

System V信号量

引言 当我们谈论System V信号量的时候,所指的是计数信号量集(posix信号量就是单个的).内核为每个信号量集维护一个数据结构.为什么说是一个信号量集呢?可以看看下面的数据结构. 数据结构示意图

System V信号量(3)

使用HttpClient进行网络处理的基本步骤如下: 1.通过get的方式获取到Response对象. CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("http://www.baidu.com/"); CloseableHttpResponse response = httpClient.execute(httpGet); 2.获取Response对

System V信号量(2)

Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性. 对于有些和操作系统相关的功能,或者是对效率要求较高的模块,我们完全可以通过C函数来实现,之后再通过Lua调用指定的C函数. 对于那些可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即typedef int (*lua_CFunction)(lua_State* L). 简单说明一下,该函数类型仅仅包含一个表示Lua环境的指针作为其唯一的参数,实现者可以通过该指针进一步获取Lua代码中实际传入的参数.返回值是整型,表示该