Linux信号量实践(1)

进程的同步与互斥

顺序程序与并发程序特征


顺序程序


并发程序


顺序性


共享性


封闭性:(运行环境的封闭性)


并发性


确定性


随机性


可再现性

进程互斥

由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥.

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。

在进程中涉及到互斥资源的程序段叫临界区.

互斥示例

说明:如果此时票数X=1,A进程与B进程同时抢到临界资源X,都执行X--,则会出现X<0的情况,这种情况肯定是不合理的,票数不可能小于0;


进程同步

进程同步指的是多个进程需要相互配合共同完成一项任务。

同步示例

说明:只有司机P1与售票员P2相互协作,才能完成,司机开车与售票员售票的过程

死锁的产生与解除

死锁是指多个进程之间相互等待对方的资源,而在得到对方资源之前又不释放自己的资源,这样,造成循环等待的一种现象。如果所有进程都在等待一个不可能发生的事,则进程就死锁了。

死锁产生的必要条件

1)互斥条件

进程对资源进行排它性的使用,即在一段时间内某资源仅为一个进程所占用。

2)请求和保持条件

当进程因请求资源而阻塞时,对已获得的资源保持不放。

3)不可剥夺条件

进程已获得的资源在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4)环路等待条件

各个进程组成封闭的环形链,每个进程都等待下一个进程所占用的资源

 

防止死锁办法

资源一次性分配(破坏请求和保持条件)

可剥夺资源(破坏不可剥夺条件)

资源有序分配法(破坏循环等待条件)

死锁避免

预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得较满意的系统性能。

由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。

信号量

信号量和P、V原语由Dijkstra(迪杰斯特拉)提出

互斥:P、V在同一个进程中

同步:P、V在不同进程中

信号量值含义

S>0:S表示可用资源的个数

S=0:表示无可用资源,无等待进程

S<0:|S|表示等待队列中进程个数

PV操作

struct semaphore
{
    int value;
    pointer_PCB queue;
}

//P原语
P(s)
{
    --s.value;
    if (s.value < 0)	//表示没有空闲资源
    {
        将当前进程设置为阻塞状态;
        将当前进程的PCB插入相应的阻塞队列s.queue末尾;
    }
}

//V原语
V(s)
{
    ++s.value;
    if (s.value <= 0)	//表示有进程处于阻塞状态
    {
        唤醒阻塞队列s.queue中等待的一个进程,将其置为就绪态;
        将其插入就绪队列;
    }
}

信号量API

Linux为信号量维护数据结构

struct semid_ds
{
    struct ipc_perm sem_perm;  /* Ownership and permissions */
    time_t          sem_otime; /* Last semop time */
    time_t          sem_ctime; /* Last change time */
    unsigned long   sem_nsems; /* No. of semaphores in set */
};

信号量集函数

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
  int semget(key_t key, int nsems, int semflg);
  int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned nsops);

semget函数

功能:用来创建和访问一个信号量集

原型

int semget(key_t key, int nsems, int semflg);

参数

key: 信号集键(key)

nsems:信号集中信号量的个数

semflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志一致

返回值:

成功返回一个非负整数,即该信号集的标识码;失败返回-1

//实践
int main()
{
    int semid = semget(0x12345670,1,0666|IPC_CREAT);
    if (semid == -1)
    {
        if (errno == EEXIST)
        {
            err_exit("EEXIST");
        }
        else
        {
           err_exit("semget error");
        }
    }
    else
    {
        cout << "semget OK" << endl;
    }

    return 0;
}

shmctl函数

功能:用于控制信号量集

原型

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

参数

semid:由semget返回的信号集标识码

semnum:信号集中信号量的序号

cmd:将要采取的动作(取值如下)

最后一个参数根据命令不同而不同

返回值:

成功返回0;失败返回-1

Man-page
       semctl()  performs  the  control operation specified by cmd on the System V semaphore set identified by semid, or on the semnum-th semaphore of that set.  (The semaphores in a set are numbered starting at 0.)
       This  function  has  three or four arguments, depending on cmd.  When there are four, the fourth has the type union semun.  The calling program must define this union as follows:

union semun
{
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

//实践:SETVAL
union mySemUn
{
    int              val;    // Value for SETVAL//
    struct semid_ds *buf;    // Buffer for IPC_STAT, IPC_SET//
    unsigned short  *array;  // Array for GETALL, SETALL//
    struct seminfo  *__buf;  // Buffer for IPC_INFO (Linux-specific)//
};

int main()
{
    int semid = semget(0x12345670,1,0666|IPC_CREAT);
    if (semid == -1)
    {
        err_exit("semget error");
    }

    union mySemUn setValue;
    setValue.val = 15764;
    if (semctl(semid,0,SETVAL,setValue) != 0)
    {
        err_exit("semctl SETVAL error");
    }

    int returnValue = semctl(semid,0,GETVAL,0);
    cout << "returnValue = " << returnValue << endl;

    return 0;
}

semop函数

功能:用来操纵一个信号量集

原型

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

参数

semid:是该信号量的标识码,也就是semget函数的返回值

sops:是个指向一个结构数组的指针

nsops:信号量的个数

返回值:

成功返回0;失败返回-1

//Man-page示例代码
    struct sembuf sops[2];
    int semid;

    /* Code to set semid omitted */

    sops[0].sem_num = 0;        /* Operate on semaphore 0 */
    sops[0].sem_op = 0;         /* Wait for value to equal 0 */
    sops[0].sem_flg = 0;

    sops[1].sem_num = 0;        /* Operate on semaphore 0 */
    sops[1].sem_op = 1;         /* Increment value by one */
    sops[1].sem_flg = 0;

    if (semop(semid, sops, 2) == -1)
    {
        perror("semop");
        exit(EXIT_FAILURE);
    }

sembuf结构体参考如下:

struct sembuf
{
    unsigned short sem_num;  /* semaphore number */
    short          sem_op;   /* semaphore operation */
    short          sem_flg;  /* operation flags */
};

sem_num是信号量的编号(从0开始)。

sem_op是信号量一次PV操作时加减的数值,一般只会用到两个值,一个是“-1”,也就是P操作,等待信号量变得可用;另一个是“+1”,也就是V操作,发出信号量已经变得可用;

sem_flag的两个取值是IPC_NOWAIT或SEM_UNDO

时间: 2024-10-02 20:07:09

Linux信号量实践(1)的相关文章

Linux信号量实践(2)

信号量API综合实践 //实践1:封装PV原语 union mySemUn { int val; // Value for SETVAL// struct semid_ds *buf; // Buffer for IPC_STAT, IPC_SET// unsigned short *array; // Array for GETALL, SETALL// struct seminfo *__buf; // Buffer for IPC_INFO (Linux-specific)// }; //

Linux及安全——Linux基础实践

Linux及安全——Linux基础实践 一.实践一:掌握软件源的维护方法,配置系统使用教育网内的软件源镜像.掌握通过软件源来查找,安装,卸载,更新软件的方法. 1.软件源的维护方法 Ubuntu的软件源列表存放在/etc/apt/sourcers.list,为了安全起见,我们在对源文件进行操作之前,先将软件源备份. 打开终端,输入命令 sudo cp /etc/apt/sources.list/ etc/apt/backup_sources.list 即把软件源备份的文件backup_sourc

Linux课题实践三——字符集总结与分析

Linux课题实践三——字符集总结与分析 20135318  刘浩晨 字符是各种文字和符号的总称,包括各国家文字.标点符号.图形符号.数字等.字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集.GB2312字符集.BIG5字符集. GB18030字符集.Unicode字符集等. 1.总结ISO.UCS/UTF.GB系列字符集的由来.异同 (1).ISO/IEC ISO/IEC 646:是国际标准化组织(ISO)及国际电工委员会(IEC)联合制定

linux信号量之进程间同步

概念 linux信号量:允许多个线程同时进入临界区,可以用于进程间的同步. 和互斥锁(mutex)的区别:互斥锁只允许一个线程进入临界区. 所在头文件:semaphore.h 主要函数 初始化函数 int sem_init(sem_t *sem, int pshared, unsigned int value) sem:要初始化的信号量 pshared:此信号量是在进程间共享还是线程间共享 value:信号量的初始值 删除函数 int sem_destroy(sem_t *sem) sem:要销

Linux基础实践

Linux基础实践 1.1 应用安装 要求:掌握软件源的维护方法,配置系统使用软件源镜像.掌握通过软件源来查找,安装,卸载,更新软件的方法 备份原地址列表文件:sudo cp /etc/apt/sources.list /etc/apt/sources.list.old 修改列表文件:sudo gedit /etc/apt/sources.list 源: deb http://mirrors.163.com/ubuntu/ trusty main multiverse restricted un

进程和程序:编写shell——《Unix/Linux编程实践教程》读书笔记(第8章)

1.Unix shell的功能 shell是一个管理进程和运行程序的程序.所有常用的shell都有3个主要功能: (1)运行程序: (2)管理输入和输出 (3)可编程 shell同时也是带有变量和流程控制的编程语言. 2.Unix的进程模型 一个程序是存储在文件中的机器指令序列,一般它是由编译器将源代码编译成二进制格式的代码.运行一个程序意味着将这些机器指令序列载入内存然后让处理器(CPU)逐条执行.在Unix术语中,一个可执行程序是一些机器指令机器数据的序列.一个进程是程序运行时的内存空间和设

系统调用操作文件——《Unix/Linux编程实践教程》读书笔记

1.who命令通过读系统日志的内容显示当前已经登录的用户. 2.Unix系统把数据存放在文件中,可以通过以下系统调用操作文件: open(filename, how) creat(filename, mode) read(fd, buffer, amt) write(fd, buffer, amt) lseek(fd, distance, base) close(fd) 3.进程对文件的读/写都要通过文件描述符,文件描述符表示文件和进程之间的连接. 4.每次系统调用都会导致用户模式和内核模式的切

终端控制和和信号——《Unix/Linux编程实践教程》读书笔记(第6章)

1.有些程序处理从特定设备来的数据.这些与特定设备相关的程序必须控制与设备的连接.Unix系统中最常见的设备是终端. 2.终端驱动程序有很多设置.各个设置的特定值决定了终端驱动程序的模式.为用户编写的程序通常需要设置终端驱动程序为特定的模式. 3.键盘输入分为3类,终端驱动程序对这些输入做不同的处理.大多数建代表常规数据,它们从驱动程序传输到程序.有些键调用驱动程序中的编辑函数.如果按下删除键,驱动程序将前一个字符从它的行缓冲中删除,并将命令发送到终端屏幕,使之从显示器中删除字符.最后,有些键调

Linux信号量详解

1.什么是信号量信号量是一种特殊的变量,访问具有原子性.只允许对它进行两个操作:1)等待信号量当信号量值为0时,程序等待:当信号量值大于0时,信号量减1,程序继续运行.2)发送信号量将信号量值加1. 我们使用信号量,来解决进程或线程间共享资源引发的同步问题. 2.Linux中信号量的使用Linux提供了一组信号量API,声明在头文件sys/sem.h中.1)semget函数:新建信号量 int semget(key_t key,int num_sems,int sem_flags); key:信