【C/C++ 信号量】进程互斥

sem.c

#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);
    printf("semid= %d \n", sem_id); 
    if (argc > 1)
    {
        // 程序第一次被调用,初始化信号量
        if (!set_semvalue())
        {
            fprintf(stderr, "Failed to initialize semaphore\n");
            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("\n%d - finished\n", 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;
    }
    printf("semctl sucess\n");
    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\n");
    }
}
 
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\n");
        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\n");
        return 0;
    }
 
    return 1;
}

king@ubuntu:~/share/ms_examples/sem$ ./sem 0 & ./sem
[1] 368505
semid= 6 
semid= 6 
semctl sucess
XXXX00XX0000XX00XX00XX00XX00XX00XX0000XX
368505 - finished

368506 - finished

进程互斥
_public.h

#ifndef __PUBLIC_HH
#define __PUBLIC_HH 1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>

using namespace std;

template <class TT, int MaxLength>
class squeue
{
    
private:
    bool m_inited;
    TT m_data[MaxLength];
    int m_head;
    int m_tail;
    int m_length;
    squeue(const squeue &) = delete;
    squeue &operator=(const squeue &) = delete;

public:

    void init()
    {
        if(m_inited !=true)
        {
            m_head = 0;
            m_tail = MaxLength - 1;
            m_length = 0;
            memset(m_data, 0, sizeof(m_data));
            m_inited = true;
        }
    }

    squeue() { init();}

    bool push(const TT &ee){
        if(full() == true){
            cout<< "循环队列已满,入队失败。\n"; return false;
        }
        m_tail=(m_tail+1)%MaxLength;
        m_data[m_tail]= ee;
        m_length++;
        return true;
    }

    int size(){
        return m_length;
    }

    bool empty()
    {
        if(m_length == 0) return true;
        return false;    
    }

    bool full()
    {
        if(m_length == MaxLength) return true;
        return false;
    }

    TT &front(){
        return m_data[m_head];
    }

    bool pop()
    {
        if(empty() == true) return false;
        m_head=(m_head+1)%MaxLength;
        m_length--;
        return true;
    }

    void printqueue()
    {
        for(int ii=0; ii< size(); ii++){
            cout<< "m_data[" << (m_head+ii)%MaxLength<<"],value="\
            << m_data[(m_head+ii)%MaxLength] << endl;
        }
    }

};

class csemp
{

private:
    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *arry;
    };

    int m_semid;
    short m_sen_flg;
    csemp(const csemp&)=delete;
    csemp &operator=(const csemp&)=delete;
public:
    csemp():m_semid(-1){}
    bool init(key_t key, unsigned short value=1, short sem_flg = SEM_UNDO);
    bool wait(short sem_op = -1);
    bool post(short sem_op = 1);
    int getvalue();
    bool destroy();
    ~csemp(){}
};


bool csemp::init(key_t key, unsigned short value, short sem_flg){
    if(m_semid != -1) return false;

    m_sen_flg = sem_flg;
    if((m_semid = semget(key, 1, 0666)) == -1)
    {
        if(errno == ENOENT)
        {
            if((m_semid = semget(key, 1, 0666 | IPC_CREAT| IPC_EXCL)) == -1)
            {
                if(errno == EEXIST)
                {
                    if(-1 == (m_semid = semget(key, 1, 0666)))
                    {
                        perror("init 1 semget()"); return false;
                    }
                    return true;
                }
                else
                {
                    perror("init 2 semget()"); return false;
                }
            }

            union semun sem_union;
            sem_union.val = value;
            if(  semctl(m_semid, 0, SETVAL, sem_union)< 0)
            {
                perror("init  semctl()"); 
                return false;
            }
        }
        else
        {
            perror("init 3 semget()"); return false; 
        } 
    }
    return true;
}


bool csemp::wait(short value){
    if(m_semid == -1) return false;
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = value;
    sem_b.sem_flg = m_sen_flg;
    if(semop(m_semid, & sem_b, 1) == -1)
    {
        perror("p semop()");
        return false;
    }
    return true;
}

bool csemp::post(short value){
    if(m_semid == -1) return false;
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = value;
    sem_b.sem_flg = m_sen_flg;
    if(semop(m_semid, & sem_b, 1) == -1)
    {
        perror("p semop()");
        return false;
    }
    return true;
}

int csemp::getvalue(){
    return semctl(m_semid, 0, GETVAL);
}

bool csemp::destroy()
{
    if(m_semid == -1) return false;
    if(semctl(m_semid, 0, IPC_RMID) == -1)
    {
        perror("destroy semctl()");
        return false;
    }
    return true;
}

#endif

#include "_public.h"

struct stgirl
{
    int no;
    char name[51];
};



int main(int argc, char *argv[])
{
    if(argc !=3 )
    {
        cout<< "Using: ./shm_samp no name\n";
        return -1;
    }
    //1. 创建共享内存 键值key为0x5005
    int shmid = shmget(0x5005, sizeof(stgirl), 0640|IPC_CREAT);
    if(shmid == -1)
    {
        cout<< " shmget(0x5005 failed. \n";
        return -1;
    }
    cout<< " shmid=" << shmid  <<endl;
    //2.把共享内存连接到当前进程的地址空间
    stgirl *ptr = (stgirl *)shmat(shmid, 0, 0);
    if(ptr == (void*)-1 )
    {
        cout<< " shmat() failed. \n";
        return -1;
    }

    //创建、初始化二元信号量
    csemp mutex;
    if(mutex.init(0x5005) == false)
    {
        cout<< "mutex.init(0x5005) failed. \n";
        return -1;
    }

    cout<<"申请加锁。。。\n";
    mutex.wait();//申请加锁
    cout<<"申请加锁成功。\n";


    //3.使用共享内存对共享内存进行读写
    cout<< "原值:no="<< ptr->no << ",name ="<< ptr->name <<endl;
    ptr->no = atoi(argv[1]);
    strcpy(ptr->name, argv[2]);
    cout<< "新值:no="<< ptr->no << ",name ="<< ptr->name <<endl;
    sleep(10);
    
    mutex.post();//解锁
    cout<<"解锁。\n";

    //4.把共享内存从当前进程分离
    shmdt(ptr);
    //5.删除共享内存
    #if 0
    if(shmtl(shmid, IPC_RMID) == -1)
    {
        cout<< " shmtl() failed. \n";
        return -1;
    }
    #endif
    return 0;
}

xshell开2个窗口 进行测试

king@ubuntu:~/share/ms_examples/sem$ ./sem_samp 1 冰冰
 shmid=5
申请加锁。。。
申请加锁成功。
原值:no=1,name =冰冰
新值:no=1,name =冰冰
解锁。

king@ubuntu:~/share/ms_examples/sem$ ./sem_samp 2 幂幂
 shmid=5
申请加锁。。。
申请加锁成功。
原值:no=1,name =冰冰
新值:no=2,name =幂幂
解锁。

#删除信号量
ipcrm -s 5 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值