⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sem.c

📁 信号量的基本操作是我在学习linux编程时写的
💻 C
字号:

/**********************************************************************
*FileName: sem.c
*    
*Perpose : 通过信号量来同步进程,让两个进程分别输出aaa bbb.
*          直到用户按下Ctrl+C.这个程序的功能类似于Linus在
*          开始写Linux时写的第一个版本.不过Linux是在保护模
*          式下,通过时钟中断来实现的.这个程序只是通过操作系
*          统提供的system call来实现.所以很简单!!!
* 
*Author  : 刘海洋
*Version : 2008-11-08 第一版
*
*Addition: 这里创建了一个信号量集,这个信号量集包含了一个信号量
*          并且信号量的最大值为1, 所以这里的信号量可以理解为互斥体
**********************************************************************/

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

#include <errno.h>

#define SEMPERM 0600   /* 八进制,所以前面的0不能省略 */

typedef union _semun
{
    int val;
    struct semid_ds *buf;
    ushort *array;
}semun;

/*
===============
 初始化信号量 
===============
*/
int initsem(key_t semkey)
{
    int status = 0;
    int semid; 
    
    /* 试着创建一个信号量 */
    semid = semget(semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL);
    if (semid == -1) /* 创建失败 */
    {
        if (errno == EEXIST) /* 如果存在,试着获取它 */
        {
            semid = semget(semkey, 1, 0);
        }
    }
    else /* 创建成功,则给信号量赋初值 */
    {
        semun arg;
        arg.val = 1;
        status == semctl(semid, 0, SETVAL, arg);
    }
    
    if (semid == -1 || status == -1)
    {
        perror("init semaphore failed!\n");
        exit(-1);
    }
    
    return semid;
}

/* 
=============
 信号量P操作 
=============
*/
int p(int semid)
{
    struct sembuf p_buf;
      
    p_buf.sem_num = 0;
    p_buf.sem_op  = -1;
    p_buf.sem_flg = SEM_UNDO;
    
    if (semop(semid, &p_buf, 1) == -1)
    {
        perror("semaphore p operation failed\n");
        exit(-1);
    }
    return 0;
}

/* 
=============
 信号量v操作 
=============
*/
int v(int semid)
{
    struct sembuf p_buf;
    
    p_buf.sem_num = 0;
    p_buf.sem_op  = 1;
    p_buf.sem_flg = SEM_UNDO;
    
    if (semop(semid, &p_buf, 1) == -1)
    {
        perror("semaphore v operation failed\n");
        exit(-1);
    }
    return 0;
}

/*
=============
 删除信号量
=============
*/
int rmsem(int semid)
{
	semun sem;
	sem.val = 0;

    if (semctl(semid, 0, IPC_RMID, sem) == -1)
    {
        perror("remove semaphore failed\n");
        exit(-1);
    }
    return 0;
}

/* 
========================
 通过信号量同步循环输出 
========================
*/
int printbysem(int semid, char *str)
{   
    while (1)
    {
        p(semid); /* Note */
        
        printf("%s", str);
        
        sleep(1);
        v(semid); /* Note */
        sleep(1);
    }
	return 0;
}

/*
==================================
 在sigint中删除信号量时,需要指定ID 
==================================
*/
int g_sem_id = 0;

/* 
==============
 中断信号处理 
==============
*/
void sigint(int signo)
{
	rmsem(g_sem_id);
	printf("\n");
	exit(0);
}

/*
===============
 Program Entry
===============
*/
int main(void)
{
    key_t sem_key = 0x200;
    int semid;
    
    setbuf(stdout, NULL); /* 设置输入输出缓冲为无缓冲 */
    
    switch (fork())
    {
        case -1: /* error */
            perror("create new process failed!\n");
            break;
            
        case 0:  /* child process */
        	semid = initsem(sem_key);
            printbysem(semid, "aaa");
            break;
        
        default: /* perant process */
        	g_sem_id = semid = initsem(sem_key);
        	signal(SIGINT, sigint);  /* 只有父进程注册信号处理函数 */
            printbysem(semid, "bbb");
            break;
    }
    
    return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -