4.posix有名信号灯应用于多进程
下面就是应用Posix有名信号灯的一个小程序。用它来限制访问共享代码的进程数目。
#include<semaphore.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
voidprint(pid_t);
sem_t*sem;/*定义Posix有名信号灯*/
intval;/*定义信号灯当前值*/
intmain(intargc,char*argv[])
{
intn=0;
if(argc!=2)
{
printf(“pleaseinputafilename!/n”);
exit(1);
}
sem=sem_open(argv[1],O_CREAT,0644,2);/*打开一个信号灯,初值设为2*/
while(n++<5)/*循环创建5个子进程,使它们同步运行*/
{
if(fork()==0)
{
sem_wait(sem);/*申请信号灯*/
print(getpid());/*调用共享代码段*/
sleep(1);
sem_post(sem);/*释放信号灯*/
printf(“I’mfinished,mypidis%d/n”,getpid());
return0;
}
wait();/*等待所有子进程结束*/
sem_close(sem);
sem_unlink(argv[1]);
exit(0);
}
voidprint(pid_tpid)
{
printf(“Igetit,mypidis%d/n”,pid);
sem_getvalue(sem,&val);
printf(“Nowthevaluehave%d/n”,val);
}
|
程序编译后运行会得到如下结果:
#./8_28_2.c
Igetit,mytidis1082330304
Nowthevaluehave1
Igetit,mytidis1090718784
Nowthevaluehave0
Ifinished,mypidis1082330304
Ifinished,mypidis1090718784
Igetit,mytidis1099107264
Nowthevaluehave1
Igetit,mytidis1116841120
Nowthevaluehave0
Ifinished,mypidis1099107264
Ifinished,mypidis1116841120
Igetit,mytidis1125329600
Nowthevaluehave1
Ifinished,mypidis1125329600
二、基于内存的信号灯
前面已经介绍了Posix有名信号灯。这些信号灯由一个name参数标识,它通常指代文件系统中的某个文件。然而Posix也提供基于内存的信号灯,它们由应用程序分配信号灯的内存空间,然后由系统初始化它们的值。
7.
名称::
|
sem_init/sem_destroy
|
功能:
|
初始化/关闭信号等
|
头文件:
|
#include<semaphore.h>
|
函数原形:
|
intsem_init(sem_t*sem,intshared,unsignedintvalue);
intsem_getvalue(sem_t*sem);
|
参数:
|
sem指向信号灯的指针
shared作用范围
value信号灯初始值
|
返回值:
|
若成功则返回0,否则返回-1。
|
基
于内存的信号灯是由sem_init初始化的。sem参数指向必须由应用程序分配的sem_t变量。如果shared为0,那么待初始化的信号灯是在同一
进程的各个线程共享的,否则该信号灯是在进程间共享的。当shared为零时,该信号灯必须存放在即将使用它的所有进程都能访问的某种类型的共享内存中。
跟sem_open一样,value参数是该信号灯的初始值。
使用完一个基于内存的信号灯后,我们调用sem_destroy关闭它。
除了sem_open和sem_close外,其它的poisx有名信号灯函数都可以用于基于内存的信号灯。
注意:posix基于内存的信号灯和posix有名信号灯有一些区别,我们必须注意到这些。
1.sem_open不需要类型与shared的参数,有名信号灯总是可以在不同进程间共享的。
2.sem_init不使用任何类似于O_CREAT标志的东西,也就是说,sem_init总是初始化信号灯的值。因此,对于一个给定的信号灯,我们必须小心保证只调用一次sem_init。
3.sem_open返回一个指向某个sem_t变量的指针,该变量由函数本身分配并初始化。但sem_init的第一个参数是一个指向某个sem_t变量的指针,该变量由调用者分配,然后由sem_init函数初始化。
4.posix有
名信号灯是通过内核持续的,一个进程创建一个信号灯,另外的进程可以通过该信号灯的外部名(创建信号灯使用的文件名)来访问它。posix基于内存的信号
灯的持续性却是不定的,如果基于内存的信号灯是由单个进程内的各个线程共享的,那么该信号灯就是随进程持续的,当该进程终止时它也会消失。如果某个基于内
存的信号灯是在不同进程间同步的,该信号灯必须存放在共享内存区中,这要只要该共享内存区存在,该信号灯就存在。
5.基于内存的信号灯应用于线程很麻烦(待会你会知道为什么),而有名信号灯却很方便,基于内存的信号灯比较适合应用于一个进程的多个线程。
下面是posix基于内存的信号灯实现一个进程的各个线程间的互次。
#include<semaphore.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
#include<pthread.h>
#incude<stdlib.h>
void*thread_function(void*arg);/*线程入口函数*/
voidprint(void);/*共享资源函数*/
sem_tbin_sem;/*定义信号灯*/
intvalue;/*定义信号量的灯*/
intmain()
{
intn=0;
pthread_ta_thread;
if((sem_init(&bin_sem,0,2))!=0)/*初始化信号灯,初始值为2*/
{
perror(“sem_init”);
exit(1);
}
while(n++<5)/*循环创建5个线程*/
{
if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0)
{
perror(“Threadcreationfailed”);
exit(1);
}
}
pthread_join(a_thread,NULL);/*等待子线程返回*/
}
void*thread_function(void*arg)
{
sem_wait(&bin_sem);/*等待信号灯*/
print();
sleep(1);
sem_post(&bin_sem);/*挂出信号灯*/
printf(“Ifinished,mypidis%d/n”,pthread_self());
pthread_exit(arg);
}
voidprint()
{
printf(“Igetit,mytidis%d/n”,pthread_self());
sem_getvalue(&bin_sem,&value);/*获取信号灯的值*/
printf(“Nowthevaluehave%d/n”,value);
}
|
posix基于内存的信号灯和有名信号灯基本是一样的,上面的几点区别就可以了。
下面是运行结果:
#gcc–lpthread–oseminitthreadseminitthread.c
#./seminitthread
Igetit,mytidis1082330304
Nowthevaluehave1
Igetit,mytidis1090718784
Nowthevaluehave0
Ifinished,mypidis1082330304
Ifinished,mypidis1090718784
Igetit,mytidis1099107264
Nowthevaluehave1
Igetit,mytidis1116841120
Nowthevaluehave0
Ifinished,mypidis1099107264
Ifinished,mypidis1116841120
Igetit,mytidis1125329600
Nowthevaluehave1
Ifinished,mypidis1125329600
下面是经典的生产者消费者问题:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
#include<sys/ipc.h>
#include<semaphore.h>
#include<fcntl.h>
#defineFIFO"myfifo"
#defineN5
intlock_var;
time_tend_time;
charbuf_r[100];
sem_tmutex,full,avail;/*定义3个信号量,full标识缓冲区是否为满,avail标识缓冲区是否为空.*/
intfd;
voidpthread1(void*arg);
voidpthread2(void*arg);
voidconsumer(void*arg);
voidproductor(void*arg);
intmain(intargc,char*argv[])
{
pthread_tid1,id2;
pthread_tmon_th_id;
intret;
end_time=time(NULL)+30;
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
printf("cannotcreatefifoserver/n");
printf("Preparingforreadingbytes.../n");
memset(buf_r,0,sizeof(buf_r));
fd=open(FIFO,O_RDWR|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(1);
}
ret=sem_init(&mutex,0,1);
ret=sem_init(&avail,0,N);
ret=sem_init(&full,0,0);
if(ret!=0)
{
perror("sem_init");
}
ret=pthread_create(&id1,NULL,(void*)productor,NULL);
if(ret!=0)
perror("pthreadcread1");
ret=pthread_create(&id2,NULL,(void*)consumer,NULL);
if(ret!=0)
perror("pthreadcread2");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
exit(0);
}
voidproductor(void*arg)
{
inti,nwrite;
while(time(NULL)<end_time){
sem_wait(&avail);
sem_wait(&mutex);
if((nwrite=write(fd,"hello",5))==-1)
{
if(errno==EAGAIN)
printf("TheFIFOhasnotbeenreadyet.Pleasetrylater/n");
}
else
printf("writehellototheFIFO/n");
sem_post(&full);
sem_post(&mutex);
sleep(1);
}
}
voidconsumer(void*arg)
{
intnolock=0;
intret,nread;
while(time(NULL)<end_time){
sem_wait(&full);
sem_wait(&mutex);
memset(buf_r,0,sizeof(buf_r));
if((nread=read(fd,buf_r,100))==-1){
if(errno==EAGAIN)
printf("nodatayet/n");
}
printf("read%sfromFIFO/n",buf_r);
sem_post(&avail);
sem_post(&mutex);
sleep(1);
}
}
|
下面是posix基于内存的信号灯实现各进程间的互斥。但要注意它并不能得到我们想要的结果。
#include<semaphore.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
voidprint(pid_t);
sem_t*sem;/*定义Posix有名信号灯*/
intval;/*定义信号灯当前值*/
intmain(intargc,char*argv[])
{
intn=0;
sem=sem_open(argv[1],O_CREAT,0644,3);/*打开一个信号灯*/
sem_getvalue(sem,&val);/*查看信号灯的值*/
printf(“Thevaluehave%d/n”,val);
while(n++<5)/*循环创建5个子进程,使它们同步运行*/
{
if(fork()==0)
{
sem_wait(sem);/*申请信号灯*/
print(getpid());/*调用共享代码段*/
sleep(1);
sem_post(sem);/*释放信号灯*/
printf(“I’mfinished,mypidis%d/n”,getpid());
return0;
}
wait();/*等待所有子进程结束*/
return0;
}
voidprint(pid_tpid)
{
printf(“Igetit,mypidis%d/n”,pid);
sem_getvalue(sem,&val);
printf(“Nowthevaluehave%d/n”,val);
}
|
下面是运行结果:
#cc–lpthread–osemsem.c
#./sem
Thevaluehave3
Igetit,mypidis2236
Nowthevaluehave2
Igetit,mypidis2237
Nowthevaluehave2
Igetit,mypidis2238
Nowthevaluehave2
Igetit,mypidis2239
Nowthevaluehave2
Igetit,mypidis2240
Nowthevaluehave2
I’mfinished,mypidis2236
I’mfinished,mypidis2237
I’mfinished,mypidis2238
I’mfinished,mypidis2239
I’mfinished,mypidis2240
问题在于sem信号灯不在共享内存区中。fork出来的子进程通常不共享父进程的内存空间。子进程是在父进程内存空间的拷贝上启动的,它跟共享内存不是一回事。
分享到:
相关推荐
Posix多线程编程学习笔记,重点介绍线程、信号灯、互斥量和共享内存。
Posix多线程编程学习笔记1~6,包括线程基础,线程属性,信号灯,条件变量,互斥变量,共享内存六部分内容。很有助于linux下多线程的开发。文档主要包含介绍相应的pthread接口函数,并举了部分相应的例子。
Posix多线程编程
Posix多线程编程—线程属性.doc Posix多线程编程—线程属性.doc Posix多线程编程—线程属性.doc Posix多线程编程—线程属性.doc
POSIX多线程编程入门 英文版 POSIX多线程编程入门 英文版
Posix多线程编程[总结].pdf
posix多线程程序设计源码 posix多线程程序设计源码 posix多线程程序设计源码 posix多线程程序设计源码
POSIX多线程编程指南,帮助你进行POSIX多线程编程,可以做为LINUX开发人员的参考。
posix多线程编程, 入门例子, 代码例子已经调试过
POSIX多线程程序设计,讲述在Linux平台下使用POSIX进行多线程编程的教程。
POSIX多线程程序设计随书源码,很不错的多线程编程资料
多线程编程的经典好书
posix多线程编程经典
Posix_线程编程指南,包括线程创建,取消,私有数据,同步,终止等方面
基于posix多线程编程指南
linux下pthread的多线程编程+代码,适合初学者
Posix多线程编程.pdf