Linux 信号量互斥编程

所谓信号量,其实就是一个数字。内核给这个数字赋予一定的含义,让它等于不同的值时所表示的意义不同。这样就可以用它来标示某种资源是否正被使用。信号的分类其实挺多的,主要还是二值和计数器。这里讨论二值

现在有个文件,有两个进程要同时访问它。进程A 要往里面写入 "Math class is cancel",进程B 要往里面写入“English test”。正常情况下这两个信息会被完整的写入文件中。但是如果进程A写到"Math class" 就暂停,接着B进程就开始写“English test”,最后进程A继续写剩下的“is cancel ”,那文件最后的结果就是“Math class English test is cancel”。结果显然错的离谱。究其错误的原因其实很简单,两个进程在同时公用一个资源但是又没有一种机制来控制访问的先后顺序。因为Linux 是一个多任务的系统,这中资源被多个任务同时访问的情况是非常普遍的。我们需要一种机制来控制资源能够被有序的访问。信号量就是一种实现。

信号量互斥的实现机制简单描述如下:

让两个进程在真正写入数据之前先测试信号量sig。当进程A要写入文件时,它先测试信号量sig,如果信号量sig 等于1,表示这个文件没有其他进程再使用,那么它就将这个信号量减1 让它等于0,接着直接写数据到这个文件。但是当进程B测试信号量sig 时发现它等于0 ,表示有进程在使用它,那么内核就让进程B挂起,当信号量的值被置为1时它才能继续执行写入操作。、

描述完信号量的机制就可以讨论Linux内核对于信号量的实现。

事实上linux内核关于信号量的接口还是很简洁的。就三个函数:

int semget(key_t key, int num_sems, int sem_flags);
int semop(int semid, struct sembuf *sops, size_t ops_num);

int semctl(int semid, int semnum, int command, ...);

semget函数

这个函数的功能是 创建/打开一个信号量集合,所谓集合其实就相当于数组。一个进程可能与多种资源相关联,可以用多个信号量来控制这些资源的访问。可见Linux 内核提供的信号量集合的概念是合理的。下面讨论它的参数和返回值:

返回值很简单,就是一个整型数----信号量标识符,标识符是内核为每个打开了的信号量集合而分配的,访问某个信号量集合就得靠它了(类比文件编程里的文件描述符)。key参数:键值。内核为所有的信号量集合维护了不同的键值,不管信号量集合是否被打开,这个键值都存在。键值其实就相当于文件名,但是键值是个整数,它可以自由指定,只是自由指定容易使得不同的信号量拥有相同的键值。因此内核提供了一个函数来分配键值:key_t ftok(const char *pathname, int proj_num);这个函数合成键值的机制简单描述下:

根据文件名pathname在内核中表示的数字以及proj_num共同合成一个键值key 并返回给调用者。num_sems参数:表明这个信号量集合的信号量个数。sem_flags参数:打开的标志,可以取值IPC_CREAT。当函数调用中有这个参数,并且键值指定的信号量集合不存在,那么这个函数就创建一个key 表示的信号量集合。

semop 函数

semop 函数用来信号量集合。事实上信号量集合的操作很简单,无非就是将信号量加一或者减一,来分别表示释放或者获取信号量。返回值除了表示操作的成败,没有什么意义。semid 参数:打开的信号量集合的标识符,从semget 返回。ops_num 参数:表示这个操作函数操作多少个信号量,因为信号量集合可能有多个信号量。 ops执行的结构体定义如下:

struct  sembuf

{

unsigned short   sem_num;//表明这个信号量在信号量集合中是哪一个

short       sem_op;     //表明操作类型    整数表明+1, 负数表明-1。事实上获取信号量和释放                                                    信号量就是在这里区别

short        sem_flg;

}

semctl 函数

semctl函数是在信号量上执行的多种操作。semid参数:表明要操作的信号量集合的标识符。semnum参数:表明要操作的信号量个数。command参数:表明要执行的命令。当我们要给信号量赋初值时可以令command == SETVAL,然后在省略参数给出要赋的值。

函数说明完了,下面给出一个简单的实例测试一下信号量互斥编程:

进程A:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main()
{
    int fd = 0;
    key_t key;
    int semid;
    struct sembuf sops;

   //创建并打开信号量
    key = ftok("/home",1);
    semid = semget(key,1,IPC_CREAT);

    semctl(semid,0,SETVAL,1);
    /* 0.打开公示栏*/
    fd = open("./board.txt",O_RDWR|O_APPEND);

    //获取信号量
    sops.sem_num = 0;
    sops.sem_op = -1;
    semop(semid,&sops,1);

    /* 1. 写入“数学课” */
    write(fd,"Math class",11);    

    /* 2. 暂停 */
    sleep(10);

    /* 3. 写入“取消”*/
    write(fd,"is cancel",10);

    //释放信号量
    sops.sem_num = 0;
    sops.sem_op = 1;
    semop(semid,&sops,1);    

    /* 4. 关闭公示栏 */
    close(fd);

    return 0;
}

进程B:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main()
{
    int fd = 0;
    key_t key;
    int semid;
    struct sembuf sops;   

    /* 0.打开公示栏 */
    fd = open("./board.txt",O_RDWR|O_APPEND);

    //打开信号量
    key = ftok("/home",1);
    semid = semget(key,1,IPC_CREAT);

    //获取信号量
    sops.sem_num = 0;
    sops.sem_op = -1;
    semop(semid,&sops,1);

    /* 1. 写入“英语课” */
    write(fd,"Enclish exam",13);

    //释放信号量
    sops.sem_num = 0;
    sops.sem_op = 1;
    semop(semid,&sops,1);      

    /* 2. 关闭公示栏 */
    close(fd);

    return 0;
}

时间: 2024-08-07 16:46:35

Linux 信号量互斥编程的相关文章

linux应用开发-信号量互斥编程

linux应用开发-信号量互斥编程 一 相应的函数 1 创建/打开信号量集合 函数名 semget 函数原形 int semget(key_t key, int nsems, int semflg) 函数功能 获取信号量集合的标识符 当key所指的信号量不存在的时候,且semflg里包含了IPC_CREAT,就会创建一个信号量的集合 所属头文件 <sys/types.h> <sys/ipc.h> <sys/sem.h> 返回值 成功返回信号量的标识符 失败返回-1 参数

Linux 信号量同步编程

前一篇文章概述了Linux 系统中信号量互斥编程,这篇文章正好是前一篇的姊妹篇----信号量同步.说它们是姊妹篇是因为它们都是利用了内核的信号量机制实现了进程间的通信.因为两者所解决的问题不同,因此它们使用的场景就会有所区别. 信号量互斥主要解决的问题是:进程间需要同时访问某种资源,但是它们对资源的操作会互相影响对方的操作结果,因此需要一种机制实现让进程在访问资源时能禁止其他进程访问相同的资源.而信号量同步则解决了另一个经典问题:生产者和消费者之间的协同工作问题. 首先描述一下生产者和消费者问题

第三季-第16课-信号量互斥编程

第16课-信号量互斥编程 16.1 公示栏问题(问题引入) 1. 问题描述 这里面我们举一个小例子.在一个班级里就有一个公示栏,A同学想写“数学课考试”,B同学想写“英语课取消”.但是有一个时间,A同学只写下了“数学课”三个字,没来得及写后面的内容就出去了,但是这个时候B同学来写下了“英语课取消”.这样让同学们看来就成了“数学课英语课取消”,给班级的其他同学造成了歧义. 这也就是我们说的同时访问一个资源,造成了,数据的混乱.若是有多个进程同时访问一个资源,同样会造成这个问题. 2. 问题程序化

信号量互斥编程

在程序中利用信号量互斥来解决公示板问题 背景知识 1.信号灯的概念 信号灯,又被称为信号量(semaphore),是IPC(进程间通信)的方式之一.它可以用来保证两个或多个关键代码段不被多个进程并发调用.每个信号灯都有个semval,用于记录信号灯的值.在进入一个关键代码段之前,进程必须获取一个信号量,使semval减1:一旦该关键代码段完成了,那么该进程必须释放信号量,使semval加1.其它想进入该关键代码段的进程,如果semval是0,就必须等待直到第一个进程释放信号量. 2.信号灯的用法

16.信号量互斥编程

我们先来看一个例子.就是两个进程访问同一个文件,由于线程的先后,导致内容的异常.即是数据内容的混乱. Student1.c: #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> ? void main(){ ????//open file ????int fd = 0; ????fd = open("/home/wen",O

转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥) 介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等.但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage). 一

Linux下的编程实战【转】

一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台的),进程控制与进程通信编程 1.Linux进程 Linux进程在内存中包含三部分数据:代码段.堆栈段和数据段.代码段存放了程序的代码.代码段可以为机器中运行同一程序的数个 进程共享.堆栈段存放的是子程序(函数)的返回地址.子程序的参数及程序的局部变量.而数据段则存放程序的全局变量.常数以及动态数

linux下多线程编程

最近研究mysql源码,各种锁,各种互斥,好在我去年认真学了<unix环境高级编程>, 虽然已经忘得差不多了,但是学过始终是学过,拿起来也快.写这篇文章的目的就是总结linux 下多线程编程,作为日后的参考资料. 本文将介绍linux系统下多线程编程中,线程同步的各种方法.包括: 互斥量(mutex) 读写锁 条件变量 信号量 文件互斥 在介绍不同的线程同步的方法之前,先简单的介绍一下进程和线程的概念, 它们的优缺点,线程相关的API,读者——写者问题和哲学家就餐问题. 基础知识 1. 进程和

Linux下socket编程,附带tcp例子

1.网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用(Solaris门和Sun RPC) 但这些都不是本文的主题!我们要讨论的是网络中进程之间如何通信?首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的.其实TCP/IP协议族已经帮我们解决了这个问