信号量实例—互斥

//account.h

#ifndef     _ACCOUNT_H
#define     _ACCOUNT_H


typedef struct{
    int code;
    double balance;    
    //定义一把互斥锁,用来对多线程操作的银行账户(共享资源)进行加锁(保护)的
    
    /* 建议一把互斥锁和一个共享资源(银行账户)绑定,尽量不要设置成全局变量,否则可能出现
    一把互斥锁去锁几百个账户(即一个线程获得锁,其他线程将阻塞),导致并发性的降低 
    */
    int semid;
}Account;


//取款
extern double get_momney(Account *a, double momney);

//存款
extern double save_momney(Account *a, double momney);

//获得余额
extern double get_balance(Account *a);

#endif
//account.c

#include "account.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "pv.h"


//取款
extern double get_momney(Account *a, double momney)
{
    if(a == NULL){
        printf("get_momney failed\n");
    }
    P(a->semid, 0, 1);
    if(momney < 0 || a->balance < momney)
    {
        printf("momney not enough\n");
        V(a->semid, 0, 1);
        return 0.0;
    }
    
    double balance = a->balance;
    sleep(1);
    balance = balance - momney;
    a->balance = balance;
    V(a->semid, 0, 1);
    return momney;
}


//存款
extern double save_momney(Account *a, double momney)
{
    if(a == NULL){
        printf("save_momney failed\n");
    }
    P(a->semid, 0, 1);
    if(momney < 0){
        V(a->semid, 0, 1);
        return 0.0;
    }
    
    double balance = a->balance;
    sleep(1);
    balance = balance + momney;
    a->balance = balance;
    V(a->semid, 0, 1);
    return momney;
}


//获得余额
extern double get_balance(Account *a)
{
    if(a == NULL){
        printf("get_balance failed\n");
    }
    P(a->semid, 0, 1);
    double balance = a->balance;
    V(a->semid, 0, 1);
    return balance;
}
//pv.h

#ifndef _PV_H_
#define _PV_H_
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>


//int semget(key_t key, int nsems, int semflg)
//初始化信号量集
extern int I(int nsems, int value);

//P操作
extern void P(int semid, int semno, int value);

//V操作
extern void V(int semid, int semno, int value);

//删除信号量集
extern void D(int semid);

#endif
//pv.c

#include "pv.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>




union semun{//根据cmd来确定联合体中的值,只能有一个
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

//int semget(key_t key, int nsems, int semflg)
//创建并初始化信号量集
int I(int nsems, int value)
{
    key_t key = ftok(".", 0);
    int semid = semget(key, nsems, IPC_CREAT|IPC_EXCL|0777);//nsems:表示信号量的个数
    if(semid < 0){
        perror("semget failed");
        return -1;
    }
    
    //int semctl(int semid,int semnum,int cmd,.../*union semun arg*/)
    unsigned short array[nsems];
    union semun u;
    for(int i = 0; i < nsems; i++){
        array[i] = value;
    }
    u.array = array;//信号量的初值
    if(semctl(semid, 0, SETALL, u) < 0){//0:表示对信号量集中的所有信号 SETALL:表示对信号量集中的所有信号量赋初值
        perror("semctl failed");
        return -1;
    }
    return semid;
}

//P操作,对信号量集中的第semno的信号量作p操作,semno:0表示第一个信号量
void P(int semid, int semno, int value)
{
    //int semop(int semid,struct sembuf *sops,size_t nsops)
    /*struct sembuf{
    unsigned short sem_num;//信号量集中信号量的编号(即哪个信号量)
    short sem_op;//正数为V操作(加操作,1为加1操作,2为加2操作),负数为P操作(减操作,-1为减1操作,-2为减2操作)
    short sem_flg;
  } */    
    struct sembuf sb[] = {{semno, -value, SEM_UNDO}};//semno:0表示第一个信号量
    if(semop(semid, sb, sizeof(sb)/sizeof(struct sembuf)) < 0){
        perror("semopp failed");
    }
    
}

//V操作
void V(int semid, int semno, int value)
{
    struct sembuf sb[] = {{semno, value, SEM_UNDO}};
    if(semop(semid, sb, sizeof(sb)/sizeof(struct sembuf)) < 0){
        perror("semopv failed");
    }
    
}

//删除信号量集
void D(int semid)
{
    if(semctl(semid, 0, IPC_RMID, NULL) < 0){
        perror("semctl failed");
    }    
}
//account_test.c

#include <stdio.h>
#include "account.h"
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "pv.h"
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>



int main()
{    
    pid_t pid ;
    
    key_t key = ftok("/etc/passwd",1);
    int shmid = shmget(key, sizeof(Account), IPC_CREAT|IPC_EXCL|0777);
    
    Account *a = (Account *)shmat(shmid, NULL, 0);
    a->code = 1001;
    a->balance = 10000.0;
    a->semid = I(1, 1);
    
    pid = fork();
    if(pid < 0){
        perror("creat fork");
    }else if(pid == 0){//child  process
        double money = get_momney(a, 10000);
        printf("child get %d from %f\n",a->code, money);
        printf("get balance = %f\n",get_balance(a));
        shmdt(a);
    }else{//father process
        double money = get_momney(a, 10000);
        printf("father get %d from %f\n",a->code, money);
        printf("get balance = %f\n",get_balance(a));
        wait(NULL);
        D(a->semid);
        shmdt(a);        
        shmctl(shmid, IPC_RMID,NULL);
    }
    
    
    
    return 0;
}

 

posted @ 2023-03-29 22:50  踏浪而来的人  阅读(56)  评论(0编辑  收藏  举报