Linux信号量

Linux信号量,第1张

信号量是包含一个非负整数型的变量,并且带有两个原子操作wait和signal。Wait还可以被称为down、P或lock,signal还可以被称为up、V、unlock或post。在UNIX的API中(POSIX标准)用的是wait和post。

对于wait操作,如果信号量的非负整形变量S大于0,wait就将其减1,如果S等于0,wait就将调用线程阻塞;对于post操作,如果有线程在信号量上阻塞(此时S等于0),post就会解除对某个等待线程的阻塞,使其从wait中返回,如果没有线程阻塞在信号量上,post就将S加1.

由此可见,S可以被理解为一种资源的数量,信号量即是通过控制这种资源的分配来实现互斥和同步的。如果把S设为1,那么信号量即可使多线程并发运行。另外,信号量不仅允许使用者申请和释放资源,而且还允许使用者创造资源,这就赋予了信号量实现同步的功能。可见信号量的功能要比互斥量丰富许多。

POSIX信号量是一个sem_t类型的变量,但POSIX有两种信号量的实现机制: 无名信号量 命名信号量 。无名信号量只可以在共享内存的情况下,比如实现进程中各个线程之间的互斥和同步,因此无名信号量也被称作基于内存的信号量;命名信号量通常用于不共享内存的情况下,比如进程间通信。

同时,在创建信号量时,根据信号量取值的不同,POSIX信号量还可以分为:

下面是POSIX信号量函数接口:

信号量的函数都以sem_开头,线程中使用的基本信号函数有4个,他们都声明在头文件semaphore.h中,该头文件定义了用于信号量操作的sem_t类型:

【sem_init函数】:

该函数用于创建信号量,原型如下:

该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示信号量是当前进程的局部信号量,否则信号量就可以在多个进程间共享,value为sem的初始值。

该函数调用成功返回0,失败返回-1。

【sem_destroy函数】:

该函数用于对用完的信号量进行清理,其原型如下:

成功返回0,失败返回-1。

【sem_wait函数】:

该函数用于以原子操作的方式将信号量的值减1。原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。其原型如下:

sem指向的对象是sem_init调用初始化的信号量。调用成功返回0,失败返回-1。

sem_trywait()则是sem_wait()的非阻塞版本,当条件不满足时(信号量为0时),该函数直接返回EAGAIN错误而不会阻塞等待。

sem_timedwait()功能与sem_wait()类似,只是在指定的abs_timeout时间内等待,超过时间则直接返回ETIMEDOUT错误。

【sem_post函数】:

该函数用于以原子操作的方式将信号量的值加1,其原型如下:

与sem_wait一样,sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1。

【sem_getvalue函数】:

该函数返回当前信号量的值,通过restrict输出参数返回。如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。

【实例1】:

【实例2】:

之所以称为命名信号量,是因为它有一个名字、一个用户ID、一个组ID和权限。这些是提供给不共享内存的那些进程使用命名信号量的接口。命名信号量的名字是一个遵守路径名构造规则的字符串。

【sem_open函数】:

该函数用于创建或打开一个命名信号量,其原型如下:

参数name是一个标识信号量的字符串。参数oflag用来确定是创建信号量还是连接已有的信号量。

oflag的参数可以为0,O_CREAT或O_EXCL:如果为0,表示打开一个已存在的信号量;如果为O_CREAT,表示如果信号量不存在就创建一个信号量,如果存在则打开被返回,此时mode和value都需要指定;如果为O_CREAT|O_EXCL,表示如果信号量存在则返回错误。

mode参数用于创建信号量时指定信号量的权限位,和open函数一样,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。

value表示创建信号量时,信号量的初始值。

【sem_close函数】:

该函数用于关闭命名信号量:

单个程序可以用sem_close函数关闭命名信号量,但是这样做并不能将信号量从系统中删除,因为命名信号量在单个程序执行之外是具有持久性的。当进程调用_exit、exit、exec或从main返回时,进程打开的命名信号量同样会被关闭。

【sem_unlink函数】:

sem_unlink函数用于在所有进程关闭了命名信号量之后,将信号量从系统中删除:

【信号量操作函数】:

与无名信号量一样,操作信号量的函数如下:

命名信号量是随内核持续的。当命名信号量创建后,即使当前没有进程打开某个信号量,它的值依然保持,直到内核重新自举或调用sem_unlink()删除该信号量。

无名信号量的持续性要根据信号量在内存中的位置确定:

很多时候信号量、互斥量和条件变量都可以在某种应用中使用,那这三者的差异有哪些呢?下面列出了这三者之间的差异:

下,应该差不多

一、如何建立线程

用到的头文件

(a)pthread.h

(b)semaphore.h

(c) stdio.h

(d)string.h

定义线程标识

pthread_t

创建线程

pthread_create

对应了一个函数作为线程的程序段

注意的问题

要保证进程不结束(在创建线程后加死循环)

在线程中加入While(1)语句,也就是死循环,保证进程不结束。

二、控制线程并发的函数

sem_t:信号量的类型

sem_init:初始化信号量

sem_wait:相当于P操作

sem_post:相当于V操作

三、实现原形系统

父亲、母亲、儿子和女儿的题目:

桌上有一只盘子,每次只能放入一只水果。爸爸专放苹果,妈妈专放橘子,一个儿子专等吃盘子中的橘子,一个女儿专等吃盘子中的苹果。分别用P,V操作和管程实现

每个对应一个线程

pthread_t father father进程

pthread_t mother mother进程

pthread_t son son进程

pthread_t daughter daughter进程

盘子可以用一个变量表示

sem_t empty

各线程不是只做一次,可以是无限或有限次循环

用While(1)控制各线程无限次循环

输出每次是那个线程执行的信息

printf("%s\n",(char *)arg)通过参数arg输出对应线程执行信息

编译方法

gcc hex.c -lpthread

生成默认的可执行文件a.out

输入./a.out命令运行

查看结果:程序连续运行显示出

father input an apple.

daughter get an apple.

mother input an orange.

son get an orange.

mother input an orange.

son get an orange.

………………..

四、程序源代码

#include <stdio.h>

#include<string.h>

#include <semaphore.h>

#include <pthread.h>

sem_t empty //定义信号量

sem_t applefull

sem_t orangefull

void *procf(void *arg) //father线程

{

while(1){

sem_wait(&empty)//P操作

printf("%s\n",(char *)arg)

sem_post(&applefull)//V操作

sleep(7)

}

}

void *procm(void *arg) //mother线程

{

while(1){

sem_wait(&empty)

printf("%s\n",(char *)arg)

sem_post(&orangefull)

sleep(3)

}

}

void *procs(void *arg) //son线程

{

while(1){

sem_wait(&orangefull)

printf("%s\n",(char *)arg)

sem_post(&empty)

sleep(2)

}

}

void *procd(void *arg) //daughter线程

{

while(1){

sem_wait(&applefull)

printf("%s\n",(char *)arg)

sem_post(&empty)

sleep(5)

}

}

main()

{

pthread_t father //定义线程

pthread_t mother

pthread_t son

pthread_t daughter

sem_init(&empty, 0, 1) //信号量初始化

sem_init(&applefull, 0, 0)

sem_init(&orangefull, 0, 0)

pthread_create(&father,NULL,procf,"father input an apple.") //创建线程

pthread_create(&mother,NULL,procm,"mother input an orange.")

pthread_create(&daughter,NULL,procd,"daughter get an apple.")

pthread_create(&son,NULL,procs,"son get an orange.")

while(1){} //循环等待

}

另外,站长团上有产品团购,便宜有保证

它的原型为: extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value))

头文件为: #include <semaphore.h>

sem为指向信号量结构的一个指针;

pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;

value给出了信号量的初始值。

函数sem_post( sem_t *sem )用来增加信号量的值当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不再阻塞,选择机制同样是由线程的调度策略决定的。

函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。

函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。

函数sem_destroy(sem_t *sem)用来释放信号量sem。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/177239.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-27
下一篇2023-03-27

发表评论

登录后才能评论

评论列表(0条)

    保存