《UNIX网络编程 卷2》读书笔记(五)

None.gifvoidmy_lock(intfd)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
structflocklock;
InBlock.gif
InBlock.gif
lock.l_type=F_WRLCK;
InBlock.gif
lock.l_whence=SEEK_SET;
InBlock.gif
lock.l_start=0;
ExpandedSubBlockStart.gifContractedSubBlock.gif
lock.l_len=0;/**//*writelockentirefile*/
InBlock.gif
InBlock.gifFcntl(fd,F_SETLKW,
&lock);
ExpandedBlockEnd.gif}

None.gif
None.gif
voidmy_unlock(intfd)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
structflocklock;
InBlock.gif
InBlock.gif
lock.l_type=F_UNLCK;
InBlock.gif
lock.l_whence=SEEK_SET;
InBlock.gif
lock.l_start=0;
ExpandedSubBlockStart.gifContractedSubBlock.gif
lock.l_len=0;/**//*unlockentirefile*/
InBlock.gif
InBlock.gifFcntl(fd,F_SETLK,
&lock);
ExpandedBlockEnd.gif}

None.gif

None.gifstaticvoidrwlock_cancelrdwait(void*arg)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gifpthread_rwlock_t
*rw;
InBlock.gif
InBlock.gifrw
=arg;
InBlock.gifrw
->rw_nwaitreaders--;
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**//*endrwlock_cancelrdwait*/
None.gif
None.gif
intpthread_rwlock_rdlock(pthread_rwlock_t*rw)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
intresult;
InBlock.gif
InBlock.gif
if(rw->rw_magic!=RW_MAGIC)
InBlock.gif
return(EINVAL);
InBlock.gif
InBlock.gif
if((result=pthread_mutex_lock(&rw->rw_mutex))!=0)
InBlock.gif
return(result);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4givepreferencetowaitingwriters*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
while(rw->rw_refcount<0||rw->rw_nwaitwriters>0)dot.gif{
InBlock.gifrw
->rw_nwaitreaders++;
InBlock.gifpthread_cleanup_push(rwlock_cancelrdwait,(
void*)rw);
InBlock.gifresult
=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);
InBlock.gifpthread_cleanup_pop(
0);
InBlock.gifrw
->rw_nwaitreaders--;
InBlock.gif
if(result!=0)
InBlock.gif
break;
ExpandedSubBlockEnd.gif}

InBlock.gif
if(result==0)
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount++;/**//*anotherreaderhasareadlock*/
InBlock.gif
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(0);
ExpandedBlockEnd.gif}

None.gif

None.gifstaticvoidrwlock_cancelwrwait(void*arg)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gifpthread_rwlock_t
*rw;
InBlock.gif
InBlock.gifrw
=arg;
InBlock.gifrw
->rw_nwaitwriters--;
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**//*endrwlock_cancelwrwait*/
None.gif
None.gif
intpthread_rwlock_wrlock(pthread_rwlock_t*rw)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
intresult;
InBlock.gif
InBlock.gif
if(rw->rw_magic!=RW_MAGIC)
InBlock.gif
return(EINVAL);
InBlock.gif
InBlock.gif
if((result=pthread_mutex_lock(&rw->rw_mutex))==-1)
InBlock.gif
return(result);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
while(rw->rw_refcount!=0)dot.gif{
InBlock.gifrw
->rw_nwaitwriters++;
InBlock.gifpthread_cleanup_push(rwlock_cancelwrwait,(
void*)rw);
InBlock.gifresult
=pthread_cond_wait(&rw->rw_condwriters,&rw->rw_mutex);
InBlock.gifpthread_cleanup_pop(
0);
InBlock.gifrw
->rw_nwaitwriters--;
InBlock.gif
if(result!=0)
InBlock.gif
break;
ExpandedSubBlockEnd.gif}

InBlock.gif
if(result==0)
InBlock.gifrw
->rw_refcount=-1;
InBlock.gif
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(0);
ExpandedBlockEnd.gif}

None.gif

如果想让进程只有一个拷贝运行,可以维护一个文件,在进程运行时先对其记录上写锁,则其他拷贝就无法获取到写锁,也就无法运行其他拷贝。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

None.gif#include"unpipc.h"
None.gif
#definePATH_PIDFILE"pidfile"
None.gif
intmain(intargc,char**argv)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
intpidfd;
InBlock.gif
charline[MAXLINE];
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4openthePIDfile,createifnonexistent*/
InBlock.gifpidfd
=Open(PATH_PIDFILE,O_RDWR|O_CREAT,FILE_MODE);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4trytowritelocktheentirefile*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(write_lock(pidfd,0,SEEK_SET,0)<0)dot.gif{
InBlock.gif
if(errno==EACCES||errno==EAGAIN)
InBlock.giferr_quit(
"unabletolock%s,is%salreadyrunning?",
InBlock.gifPATH_PIDFILE,argv[
0]);
InBlock.gif
else
InBlock.giferr_sys(
"unabletolock%s",PATH_PIDFILE);
ExpandedSubBlockEnd.gif}

ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4writemyPID,leavefileopentoholdthewritelock*/
InBlock.gifsnprintf(line,
sizeof(line),"%ld/n",(long)getpid());
InBlock.gifFtruncate(pidfd,
0);
InBlock.gifWrite(pidfd,line,strlen(line));
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*thendowhateverthedaemondoesdot.gif*/
InBlock.gif
InBlock.gifpause();
ExpandedBlockEnd.gif}

None.gif

当然一个守护进程防止自身另一个拷贝的启动还有其他方法,比如可以使用信号灯。

若以O_CREATEO_EXCL来调用open函数,则若文件存在,就返回一个错误,我们可以用这个技巧来将文件作为锁用。

None.gif#include"unpipc.h"
None.gif
None.gif
#defineLOCKFILE"/tmp/seqno.lock"
None.gif
None.gif
voidmy_lock(intfd)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
inttempfd;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
while((tempfd=open(LOCKFILE,O_RDWR|O_CREAT|O_EXCL,FILE_MODE))<0)dot.gif{
InBlock.gif
if(errno!=EEXIST)
InBlock.giferr_sys(
"openerrorforlockfile");
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*someoneelsehasthelock,looparoundandtryagain*/
ExpandedSubBlockEnd.gif}

ExpandedSubBlockStart.gifContractedSubBlock.gifClose(tempfd);
/**//*openedthefile,wehavethelock*/
ExpandedBlockEnd.gif}

None.gif
None.gif
voidmy_unlock(intfd)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gifUnlink(LOCKFILE);
/**//*releaselockbyremovingfile*/
ExpandedBlockEnd.gif}

None.gif
None.gif


这种技巧有三个问题:

1,若持有该锁的进程没有释放锁就终止了,则此文件名没有被删除,对于这个问有一些办法,比如检查文件的最近访问时间,若大于某个阀值,则认定它已经被遗忘了。另一个办法是把持有锁的进程ID写入锁文件中,则其他进程可以读出该进程ID,并去检查进程是否还在运行,但这也有问题,因为进程ID在过一段时间后是会重用的。但这些情形对于fcntl记录上锁来说都不成问题,因为进程终止时,它持有的记录锁都自动释放。

2,若已经有另外一个进程打开了锁文件,则当前进程只是在一个无限循环中不断调用open,也就是轮询。一个替代技巧是sleep一下,再尝试open.当然若使用fcntl进行记录上锁,这不成问题,只要想持有锁的进程指定FSETLKW命令,那么内核将把该进程投入睡眠,直到锁可用再唤醒它。

3,调用openunlink创建和删除额外一个文件涉及文件系统的访问,这比调用fcntl两次(一个获取锁,一次释放锁)所花时间长得多。

互斥锁和信号量的区别是:互斥锁必须总是由锁住它的线程来解锁,但信号量的signal却不必由执行过它的wait操作的同一个线程来执行。

阅读更多

没有更多推荐了,返回首页