Posix信号灯
<!--[if !supportLists]-->1、
<!--[endif]-->函数列表(#include <semaphore.h>)
有名信号灯特异函数
<!--[if !supportLists]-->Ø
<!--[endif]-->sem_t *sem_open(const char *name, int
oflag);
sem_t *sem_open(const char *name, int oflag,mode_t
mode, unsigned int value);
此函数创建一个新的信号灯或打开一个已存在的有名信号灯,成功时返回指向信号灯的指针,出错时返回SEM_FAILED。
Oflag可以为0、O_CREATE、O_CREATE|O_EXCL。如果O_CREATE,当信号灯存在时,则不初始化它,当信号灯不存在时,则创建并初始化它。如果O_CREATE|O_EXCL,当信号灯存在时,错误,当信号灯不存在时,则创建并初始化它。
Mode同FIFO的mkfifo函数,指定S_IRUSR
| S_IWUSR | S_IRGRP | S_IROTH表示FIFO允许用户读、用户写、组成员读和其他用户读。
Value为信号灯的初始值,二值信号灯的初始值通常为1,计数信号灯的初始值则往往大于1.
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_close(sem_t *sem);
此函数用于关闭有名信号灯,成功返回0,失败返回-1。
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_unlink(const char *name);
此函数用于删除有名信号灯,成功返回0,失败返回-1.
无名信号灯特异函数
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_init(sem_t *sem, int pshared,
unsigned int value);
此函数用于初始化基于内存空间的无名信号灯,成功不一定返回0,失败返回-1.
sem参数指向必须由应用程序分配的sem_t变量;
pshared为0时,那么初始化的信号灯是在同一个进程的各个线程间共享的,为1的话就是在进程间共享的,此时该信号灯必须放在即将使用他的所有进程都能访问的某种类型的共享内存区中;
跟sem_open一样,value参数是该信号灯的初始值。
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_destroy(sem_t *sem);
此函数用于销毁无名信号灯,成功返回0,失败返回-1.
公共函数
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
sem_wait测试所指信号灯,如果该值大于0,则减1并立即返回;如果等于0,调用线程进入休眠;
sem_trywait测试所指信号灯,如果该值大于0,则减1并立即返回;如果等于0,此函数返回EAGAIN错误;
sem_timedwait测试所指信号灯,如果该值大于0,则减1并立即返回;如果等于0,此函数阻塞等待abs_timeout时长,超时时,函数返回ETIMEDOUT错误,在abs_timeout内信号灯值变成大于0,则减1并立即返回。
成功时返回0,失败时返回-1.
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_post(sem_t *sem);
给该信号灯的值加1,然后唤醒等待该信号灯值变成正数的任意线程,成功时返回0,失败时返回-1。
<!--[if !supportLists]-->Ø
<!--[endif]-->int sem_getvalue(sem_t *sem, int *sval);
由sval返回所指定信号灯的值,成功返回0,失败返回-1.
<!--[if !supportLists]-->2、
<!--[endif]-->实例解析
<!--[if !supportLists]-->Ø
<!--[endif]-->namedsem.c
Posix有名信号灯在linux中没有实现。
# include <semaphore.h>
#include
<fcntl.h>
#include
<sys/types.h>
#include
<sys/stat.h>
int main(int
argc, char **argv)
{
int c, flags;
sem_t *sem;
unsigned int value;
flags = O_RDWR | O_CREAT;
value = 1;
sem =
sem_open("/tmp/sem1", flags, (S_IRUSR | S_IWUSR | S_IRGRP |
S_IROTH), value);
if(sem==SEM_FAILED)
printf("sem=%d/n",sem);
else
printf("okk!!/n");
sleep(100);
sem_close(sem);
exit(0);
}
#gcc namedsem.c –lpthread –o namedsem
|
Sem_open返回的始终为SEM_FAILED,并且在目录tmp下始终没有见到sem1文件。
<!--[if !supportLists]-->Ø
<!--[endif]-->nonamedsem.c
Posix无名信号灯的在单个线程中的基本操作。
# include
<semaphore.h>
#include
<fcntl.h>
#include
<sys/types.h>
#include
<sys/stat.h>
int main(int
argc, char **argv)
{
int a;
sem_t *sem;
int c=0;
c=sem_init(sem,0,11);
if(c==-1)
printf("sem_init
failed/n");
else
printf("sem_init
success/n");
sem_getvalue(sem,&a);
printf("a=%d/n",a);
//输出11
sem_post(sem);
sem_getvalue(sem,&a);
printf("a=%d/n",a);
//输出12
sem_wait(sem);
sem_getvalue(sem,&a);
printf("a=%d/n",a);
//输出11
sem_destroy(sem);
exit(0);
}
#gcc nonamedsem.c –lpthread –o nonamedsem
|
<!--[if !supportLists]-->Ø
<!--[endif]-->互斥与无名信号灯
在线程之间使用一个二值无名信号灯,比较于同步锁。
<!--[if gte vml 1]><v:shapetype id="_x0000_t75"
coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe"
filled="f" stroked="f">
<v:stroke joinstyle="miter" />
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0" />
<v:f eqn="sum @0 1 0" />
<v:f eqn="sum 0 0 @1" />
<v:f eqn="prod @2 1 2" />
<v:f eqn="prod @3 21600 pixelWidth" />
<v:f eqn="prod @3 21600 pixelHeight" />
<v:f eqn="sum @0 0 1" />
<v:f eqn="prod @6 1 2" />
<v:f eqn="prod @7 21600 pixelWidth" />
<v:f eqn="sum @8 21600 0" />
<v:f eqn="prod @7 21600 pixelHeight" />
<v:f eqn="sum @10 21600 0" />
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" />
<o:lock v:ext="edit" aspectratio="t" />
</v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:415.5pt;
height:102.75pt'>
<v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png" mce_src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
具体互斥例子见4、互斥和条件变量】【basicmutex】。
区别是互斥锁必须总是由锁住它的线程解锁,信号灯的挂出却不必由执行过它的等待操作的同一线程执行。
<!--[if !supportLists]-->Ø
<!--[endif]-->条件变量与无名信号灯
在线程之间使用多个二值无名信号灯,比较于条件变量。
具体条件变量例子见【4、互斥和条件变量】【basiccond】。
<!--[if gte vml 1]><v:shape
id="_x0000_i1026" type="#_x0000_t75" style='width:252pt;height:158.25pt'>
<v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image003.png" mce_src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image003.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if gte vml 1]><v:shape
id="_x0000_i1027" type="#_x0000_t75" style='width:294pt;height:171pt'>
<v:imagedata src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image005.png" mce_src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image005.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
条件变量需要绑定的同步锁以及一个特定的变量。而三个信号灯即可实现同样的功能。
<!--[if !supportLists]-->3、
<!--[endif]-->小结
<!--[if !supportLists]-->(1)
<!--[endif]-->有名信号灯与无名信号灯区别
<!--[if !supportLists]-->Ø
<!--[endif]-->有名信号灯由一个name参数标识,它通常指代文件系统中的某个文件;无名信号灯是指基于内存的信号灯,它们由应用程序分配的sem_t数据类型的内存空间,然后由系统初始化他们的值。
<!--[if !supportLists]-->Ø
<!--[endif]-->Sem_open不需要指定类似于pshared的参数或类似于 PTHREAD_PROCESS_SHARED的属性(互斥锁和条件变量可使用该属性),因为有名信号灯总是可以在不同进程间共享的。
<!--[if !supportLists]-->Ø
<!--[endif]-->Sem_open函数的作用有两个:创建和初始化有名信号灯;sem_init函数的作用只有一个:初始化无名信号灯,创建由应用程序完成。对于同一个信号灯,如果为有名,则sem_open可以调用多次,而如果为无名,则只能调用一次。
<!--[if !supportLists]-->Ø
<!--[endif]-->彼此无亲缘关系的不同进程使用信号灯时,通常使用有名信号灯,其名字就是各个进程标识信号灯的手段;基于内存的信号灯至少具有随进程的持续性,但真正持续性却取决于信号灯存放在其中的内存区的类型,只要含有某个基于内存信号灯的内存区保持有效,该信号灯就一直存在。
<!--[if !supportLists]-->(2)
<!--[endif]-->信号灯在线程进程中的使用
<!--[if !supportLists]-->Ø
<!--[endif]-->有名信号灯可以在任何线程或进程间使用,因为其实质就是文件系统中的一个文件;
<!--[if !supportLists]-->Ø
<!--[endif]-->如果基于内存的信号灯是由单个进程内的各个线程共享的(sem-init的pshared为0),那么该信号灯具有随进程的持续性,当该进程终止时,它就消失。
<!--[if !supportLists]-->Ø
<!--[endif]-->如果基于内存的信号灯是在不同进程间共享的(sem_init的pshared为1),那么该信号灯必须存放在共享内存区中,因而只要该共享内存区仍然存在,该信号灯也就继续存在。Posix和system v共享内存区都具有随内核的持续性,这意味着服务器可以创建一个共享内存区,在该共享内存区中初始化一个posix基于内存的信号灯,然后终止,一段时间后,一个或多个客户打开该共享内存区,访问存放在其中的基于内存的信号灯。
<!--[if !supportLists]-->(3)
<!--[endif]-->信号灯、互斥与条件变量区别
<!--[if !supportLists]-->Ø
<!--[endif]-->互斥锁必须总是由给它上锁的线程解锁,信号灯没有这种限制:一个线程可以等待某个给定信号灯(例如该信号灯值由1变为0,同上锁),而另一个线程可以挂出该信号灯(例如信号灯值由0变为1,同解锁)。
<!--[if !supportLists]-->Ø
<!--[endif]-->既然每个信号灯关联一个值,挂出(post)操作加1,等待(wait)操作减1,因此任何线程均可以挂出一个信号,即使当时没有线程在等待该信号灯变正数也没关系。然而,如果某个线程调用了pthread_cond_signal,如果当时没有任何线程阻塞在pthread_cond_wait调用中,那么发往相应条件变量的信号将丢失。
<!--[if !supportLists]-->Ø
<!--[endif]-->在各种各样的同步技巧(互斥锁、条件变量、读写锁、信号灯)中,能够从信号处理程序中安全调用的唯一函数是sem_post。
<!--[if !supportLists]-->Ø
<!--[endif]-->互斥锁、条件变量、读写锁、信号灯以及记录上锁都有它们各自的位置。互斥锁是为上锁锁优化的,条件变量是为等待而优化的,信号灯既可以用于上锁,也可以用于等待,因而可能导致更多的开销和更高的复杂性。
<!--[if !supportLists]-->Ø
<!--[endif]-->使用互斥锁和条件变量实现具有随内核持续性的计数信号灯需要大约300行C代码。信号灯意图进程间通信,互斥锁和条件变量意图线程间通信。
<!--[if !supportLists]-->(4)
<!--[endif]-->尽管posix有名信号灯是由可能与文件系统中的路径对应的名字来标识的,但是它们并不要求存放在文件系统内的某个文件中。例如嵌入式实时系统可能使用这样的名字来标识信号灯,但真正的信号等值却存放在内核中的某个地方。
<!--[if !supportLists]-->(5)
<!--[endif]-->Wait可以:posix术语等待(wait)、P操作、递减(down)和上锁(lock);
Post可以:posix术语挂出(post)、V操作、递增(up)和解锁(unlock)。
<!--[if !supportLists]-->(6)
<!--[endif]-->值仅为1或0的信号灯为二值信号灯;值大于1的信号灯为计数信号灯。
<!--[if !supportLists]-->(7)
<!--[endif]-->可以使用FIFO、内存映射I/O和System V信号灯实现Posix信号灯。
分享到:
相关推荐
在`posix_ipc`库中,可以创建命名或匿名的信号量,并通过`Semaphore`类来操作它们,包括`sem_open`、`sem_close`、`sem_post`(增加信号量值)和`sem_wait`(减少信号量值,如果值为0则阻塞)等函数。 2. **消息...
### System V IPC与POSIX IPC通信机制详解 #### 一、概述 在计算机科学领域,进程间通信(Inter-Process Communication, IPC)是操作系统提供的核心功能之一,它允许不同的进程之间进行数据交换和同步操作。System...
- **Posix IPC** 包括:Posix消息队列、Posix信号灯、Posix共享内存区。 #### 三、IPC机制详解 ##### 1. 管道(Pipe)及有名管道(Named Pipe) - **管道** 是用于具有亲缘关系进程间通信的一种方式,例如父进程...
虽然Java标准库没有直接支持共享内存,但可以通过JNI(Java Native Interface)调用C/C++库,如POSIX共享内存API,实现跨进程数据共享。这种方式需要开发者具备一定的C/C++编程经验。 4. **消息队列** Java没有...
使用POSIX线程(pthread)和信号量(semaphore)实现线程间的同步与互斥。 通过信号量控制对共享资源的访问,避免竞争条件。 3. 共享内存 实现基于共享内存的环形缓冲区,用于生产者消费者模型的数据传递。 ...
1. **信号量(Semaphore)**: - `sem_shm.cpp`涉及到信号量和共享内存的结合使用。信号量是一种同步机制,用于控制多个进程对共享资源的访问,防止资源的竞争条件。在C++中,可以使用POSIX的`sem_t`结构体和`sem_...
- **平台与编译器**:书中示例代码基于POSIX标准编写,适用于大多数现代UNIX系统(包括Linux)。编译时推荐使用GCC编译器。 - **官方网站**:访问[官方主页](https://beej.us/guide/bipc/)获取最新版本的文档和其他...
- Linux和Unix提供了多种IPC机制,如管道(Pipe)、有名管道(FIFO)、信号量(Semaphore)、消息队列(Message Queue)、共享内存(Shared Memory)和套接字(Socket)。 2. 管道与有名管道: - 管道是半双工...
1. 锁管理:由于共享内存可能被多个进程同时访问,因此需要使用互斥锁(mutex)或者信号量(semaphore)来确保数据的一致性。 2. 错误处理:在处理管道和共享内存时,可能出现各种错误,如创建失败、读写错误等,...
在实际应用中,使用IPC进行数据I/O有多种方式,如管道(Pipe)、信号量(Semaphore)、共享内存(Memory-Mapped File)、消息队列(Message Queue)等。在Windows上,我们通常会利用CreateFileMapping和...
在Linux环境下,有多种IPC方式,包括管道(pipe)、有名管道(FIFO)、信号(signal)、消息队列、共享内存(shared memory)以及信号量(semaphore)和套接字(socket)。下面对这些通信方式进行详细说明。 1. ...
3. **POSIX IPC**:为了标准化IPC接口,POSIX定义了一系列标准,包括线程、消息队列和信号量等。 4. **基于Socket的IPC**:适用于网络环境,同时也可用于本地进程间通信,提供了高度灵活和可移植的通信方式。 5. **...
本文将简要介绍Linux下几种主要的IPC方式:管道(pipe)和有名管道(FIFO)、信号(signal)、消息队列、共享内存(shared memory)、信号量(semaphore)以及套接字(socket)。 1. **管道(pipe)和有名管道...
posix ipc 2.1 introduction 19 2.2 ipc names 19 2.3 creating and opening ipc channels 22 2.4 ipc permissions 25 2.5 summary 26 .chapter 3. system v ipc 3.1 introduction 27 3.2 key_t keys and ...
在同步方面,Kroah-Hartman提到了多种方法,包括互斥锁(mutex)、条件变量(condition variables)、信号量(semaphore)、文件锁(file lock)、记录锁、“System V”信号量和“POSIX”信号量等。其中,互斥锁是最...
- **可移植性**:某些IPC机制如POSIX接口在不同Linux发行版间有较好的兼容性。 - **性能**:对于大量数据交换,带宽和延迟是重要的考量因素,可能需要通过实测比较不同机制的性能。 - **实时调度**:需要高实时性的...
Linux提供了多种IPC方式,如管道(pipe)、信号量(semaphore)、消息队列(message queue)、共享内存(shared memory)和套接字(socket)等。管道是一种半双工通信方式,数据只能单向流动;信号量用于同步多个...