TreeviewCopyright @doctording all right reserved, powered by aleen42

Linux 信号量实践

linux man semop

NAME
       semop, semtimedop - System V semaphore operations

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

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

       int semtimedop(int semid, struct sembuf *sops, size_t nsops,
                      const struct timespec *timeout);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       semtimedop(): _GNU_SOURCE

DESCRIPTION
       Each semaphore in a System V semaphore set has the following associated values:

       unsigned short  semval;   /* semaphore value */
       unsigned short  semzcnt;  /* # waiting for zero */
       unsigned short  semncnt;  /* # waiting for increase */
       pid_t           sempid;   /* ID of process that did last op */

信号量实现生产者消费者

伪代码

semaphore mutex=1; //临界区互斥信号量
semaphore empty=n;  //空闲缓冲区,初始值为buffer的大小
semaphore full=0;  //缓冲区初始化为空
producer () { //生产者进程
    while(1){
        produce an item in nextp;  //生产数据
        P(empty);  //获取空缓冲区单元
        P(mutex);  //进入临界区.
        add nextp to buffer;  //将数据放入缓冲区
        V(mutex);  //离开临界区,释放互斥信号量
        V(full);  //满缓冲区数加1
    }
}

consumer () {  //消费者进程
    while(1){
        P(full);  //获取满缓冲区单元
        P(mutex);  // 进入临界区
        remove an item from buffer;  //从缓冲区中取出数据
        V (mutex);  //离开临界区,释放互斥信号量
        V (empty) ;  //空缓冲区数加1
        consume the item;  //消费数据
    }
}

linux c代码实现

信号量+互斥锁实现生产者,消费者问题

  • test.cpp
#include<iostream>
#include<unistd.h>  // sleep
#include<pthread.h>
#include"semaphore.h"

using namespace std;

#define N 5

semaphore mutex("/", 1);           // 临界区互斥信号量
semaphore empty("/home", N);       // 记录空缓冲区数,初值为N
semaphore full("/home/john",0); // 记录满缓冲区数,初值为0
int buffer[N];                     // 缓冲区,大小为N
int i=0;
int j=0;

void* producer(void* arg)
{
    empty.P();                 // empty减1
    mutex.P();

    buffer[i] = 10 + rand() % 90;
    printf("Producer %d write Buffer[%d]: %d\n",(int)arg,i+1,buffer[i]);
    i = (i+1) % N;

    mutex.V();
    full.V();                  // full加1 
    return arg;
}

void* consumer(void* arg)
{
    full.P();                  // full减1
    mutex.P();

    printf("                               \033[1;31m");
    printf("Consumer %d read Buffer[%d]: %d\n",(int)arg,j+1,buffer[j]);
    printf("\033[0m");
    j = (j+1) % N;

    mutex.V();
    empty.V();                 // empty加1
    return arg;
}

int main()
{
    pthread_t id[10];

    // 开10个生产者线程,10个消费者线程
    for(int k=0; k<10; ++k)
        pthread_create(&id[k], NULL, producer, (void*)(k+1));

    for(int k=0; k<10; ++k)
        pthread_create(&id[k], NULL, consumer, (void*)(k+1));

    sleep(1);
    return 0;
}
  • semaphore.h

定义信号量类,以及P,V操作

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<sys/sem.h>
using namespace std;

// 联合体,用于semctl初始化
union semun {
    int              val; /*for SETVAL*/
    struct semid_ds *buf;
    unsigned short  *array;
};


class semaphore {
private:
    int sem_id; //信号量ID,内核中创建
    int init_sem(int);
public:
    semaphore(const char*, int); /*构造函数*/
    ~semaphore();                /*析构函数*/
    void P();                    /*P操作*/
    void V();                    /*V操作*/
};
  • semaphore.cpp
#include"semaphore.h"

semaphore::semaphore(const char* path, int value)
{
    key_t key;
    /*获取key值*/
    if((key = ftok(path, 'z')) < 0) {
        perror("ftok error");
        exit(1);
    }

    /*创建信号量集,信号量的数量为1*/
    if((sem_id = semget(key, 1, IPC_CREAT|0666)) == -1) {
        perror("semget error");
        exit(1);
    }

    init_sem(value);
}


semaphore::~semaphore()
{
    union semun tmp;
    if(semctl(sem_id, 0, IPC_RMID, tmp) == -1) {
        perror("Delete Semaphore Error");
        exit(1);
    }
}

// 获得信号量 减去1
void semaphore::P()
{
    struct sembuf sbuf;
    sbuf.sem_num = 0; /*序号*/
    sbuf.sem_op = -1; /*P操作*/
    sbuf.sem_flg = SEM_UNDO;

    if(semop(sem_id, &sbuf, 1) == -1) {
        perror("P operation Error");
    }
}

//释放信号量 加上1
void semaphore::V()
{
    struct sembuf sbuf;
    sbuf.sem_num = 0; /*序号*/
    sbuf.sem_op = 1;  /*V操作*/
    sbuf.sem_flg = SEM_UNDO;

    if(semop(sem_id, &sbuf, 1) == -1) {
        perror("V operation Error");
    }
}


// 初始化信号量
int semaphore::init_sem(int value)
{
    union semun tmp;
    tmp.val = value;
    if(semctl(sem_id, 0, SETVAL, tmp) == -1) {
        perror("Init Semaphore Error");
        return -1;
    }
    return 0;
}
  • 附:Makefile
.PHONY: build clean

CC=g++
HEADERS=-I.
DEBUG=-g -ggdb  
WALL=-Wall -W  
CFLAGS=$(WALL) $(DEBUG)  
L_CC=$(CC) $(CFLAGS) $(HEADERS)


test:test.o semaphore.o
    $(L_CC) $^ -o $@ -lpthread

%.o:%.cpp
    $(L_CC) -c $<

clean:
    @-rm *.o
    @-rm test
Copyright @doctording all right reserved,powered by Gitbookupdate at: 2020-09-05 17:23:45

results matching ""

    No results matching ""