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

时间:2022-08-04 21:06:38
《UNIX网络编程 卷2》读书笔记(五)void  my_lock( int  fd)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
struct flock    lock;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_type = F_WRLCK;
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_whence = SEEK_SET;
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_start = 0;
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
lock.l_len = 0;                /* write lock entire file */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    Fcntl(fd, F_SETLKW, 
&lock);
《UNIX网络编程 卷2》读书笔记(五)}

《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
void  my_unlock( int  fd)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
struct flock    lock;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_type = F_UNLCK;
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_whence = SEEK_SET;
《UNIX网络编程 卷2》读书笔记(五)    
lock.l_start = 0;
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
lock.l_len = 0;                /* unlock entire file */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    Fcntl(fd, F_SETLK, 
&lock);
《UNIX网络编程 卷2》读书笔记(五)}

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

《UNIX网络编程 卷2》读书笔记(五)static   void  rwlock_cancelrdwait( void   * arg)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    pthread_rwlock_t    
*rw;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    rw 
= arg;
《UNIX网络编程 卷2》读书笔记(五)    rw
->rw_nwaitreaders--;
《UNIX网络编程 卷2》读书笔记(五)    pthread_mutex_unlock(
&rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)}

《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
/* end rwlock_cancelrdwait */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
int  pthread_rwlock_rdlock(pthread_rwlock_t  * rw)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
int        result;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
if (rw->rw_magic != RW_MAGIC)
《UNIX网络编程 卷2》读书笔记(五)        
return(EINVAL);
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
if ( (result = pthread_mutex_lock(&rw->rw_mutex)) != 0)
《UNIX网络编程 卷2》读书笔记(五)        
return(result);
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        
/* 4give preference to waiting writers */
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0{
《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_nwaitreaders++;
《UNIX网络编程 卷2》读书笔记(五)        pthread_cleanup_push(rwlock_cancelrdwait, (
void *) rw);
《UNIX网络编程 卷2》读书笔记(五)        result 
= pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)        pthread_cleanup_pop(
0);
《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_nwaitreaders--;
《UNIX网络编程 卷2》读书笔记(五)        
if (result != 0)
《UNIX网络编程 卷2》读书笔记(五)            
break;
《UNIX网络编程 卷2》读书笔记(五)    }

《UNIX网络编程 卷2》读书笔记(五)    
if (result == 0)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_refcount++;        /* another reader has a read lock */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    pthread_mutex_unlock(
&rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)    
return (0);
《UNIX网络编程 卷2》读书笔记(五)}

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

《UNIX网络编程 卷2》读书笔记(五)static   void  rwlock_cancelwrwait( void   * arg)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    pthread_rwlock_t    
*rw;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    rw 
= arg;
《UNIX网络编程 卷2》读书笔记(五)    rw
->rw_nwaitwriters--;
《UNIX网络编程 卷2》读书笔记(五)    pthread_mutex_unlock(
&rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)}

《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
/* end rwlock_cancelwrwait */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
int  pthread_rwlock_wrlock(pthread_rwlock_t  * rw)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
int        result;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
if (rw->rw_magic != RW_MAGIC)
《UNIX网络编程 卷2》读书笔记(五)        
return(EINVAL);
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    
if ( (result = pthread_mutex_lock(&rw->rw_mutex)) == -1)
《UNIX网络编程 卷2》读书笔记(五)        
return(result);
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
while (rw->rw_refcount != 0{
《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_nwaitwriters++;
《UNIX网络编程 卷2》读书笔记(五)        pthread_cleanup_push(rwlock_cancelwrwait, (
void *) rw);
《UNIX网络编程 卷2》读书笔记(五)        result 
= pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)        pthread_cleanup_pop(
0);
《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_nwaitwriters--;
《UNIX网络编程 卷2》读书笔记(五)        
if (result != 0)
《UNIX网络编程 卷2》读书笔记(五)            
break;
《UNIX网络编程 卷2》读书笔记(五)    }

《UNIX网络编程 卷2》读书笔记(五)    
if (result == 0)
《UNIX网络编程 卷2》读书笔记(五)        rw
->rw_refcount = -1;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    pthread_mutex_unlock(
&rw->rw_mutex);
《UNIX网络编程 卷2》读书笔记(五)    
return(0);
《UNIX网络编程 卷2》读书笔记(五)}

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

如果想让进程只有一个拷贝运行,可以维护一个文件,在进程运行时先对其记录上写锁,则其他拷贝就无法获取到写锁,也就无法运行其他拷贝。

《UNIX网络编程 卷2》读书笔记(五)#include     " unpipc.h "
《UNIX网络编程 卷2》读书笔记(五)
#define     PATH_PIDFILE    "pidfile"
《UNIX网络编程 卷2》读书笔记(五)
int  main( int  argc,  char   ** argv)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
int        pidfd;
《UNIX网络编程 卷2》读书笔记(五)    
char    line[MAXLINE];
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        
/* 4open the PID file, create if nonexistent */
《UNIX网络编程 卷2》读书笔记(五)    pidfd 
= Open(PATH_PIDFILE, O_RDWR | O_CREAT, FILE_MODE);
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        
/* 4try to write lock the entire file */
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
if (write_lock(pidfd, 0, SEEK_SET, 0< 0{
《UNIX网络编程 卷2》读书笔记(五)        
if (errno == EACCES || errno == EAGAIN)
《UNIX网络编程 卷2》读书笔记(五)            err_quit(
"unable to lock %s, is %s already running?",
《UNIX网络编程 卷2》读书笔记(五)                     PATH_PIDFILE, argv[
0]);
《UNIX网络编程 卷2》读书笔记(五)        
else
《UNIX网络编程 卷2》读书笔记(五)            err_sys(
"unable to lock %s", PATH_PIDFILE);
《UNIX网络编程 卷2》读书笔记(五)    }

《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        
/* 4write my PID, leave file open to hold the write lock */
《UNIX网络编程 卷2》读书笔记(五)    snprintf(line, 
sizeof(line), "%ld\n", (long) getpid());
《UNIX网络编程 卷2》读书笔记(五)    Ftruncate(pidfd, 
0);
《UNIX网络编程 卷2》读书笔记(五)    Write(pidfd, line, strlen(line));
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
/* then do whatever the daemon does 《UNIX网络编程 卷2》读书笔记(五) */
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)    pause();
《UNIX网络编程 卷2》读书笔记(五)}

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

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

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

《UNIX网络编程 卷2》读书笔记(五)#include     " unpipc.h "
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
#define     LOCKFILE    "/tmp/seqno.lock"
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
void  my_lock( int  fd)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)    
int        tempfd;
《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    
while ( (tempfd = open(LOCKFILE, O_RDWR|O_CREAT|O_EXCL, FILE_MODE)) < 0{
《UNIX网络编程 卷2》读书笔记(五)        
if (errno != EEXIST)
《UNIX网络编程 卷2》读书笔记(五)            err_sys(
"open error for lock file");
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)        
/* someone else has the lock, loop around and try again */
《UNIX网络编程 卷2》读书笔记(五)    }

《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    Close(tempfd);            
/* opened the file, we have the lock */
《UNIX网络编程 卷2》读书笔记(五)}

《UNIX网络编程 卷2》读书笔记(五)
《UNIX网络编程 卷2》读书笔记(五)
void  my_unlock( int  fd)
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)
{
《UNIX网络编程 卷2》读书笔记(五)《UNIX网络编程 卷2》读书笔记(五)    Unlink(LOCKFILE);        
/* release lock by removing file */
《UNIX网络编程 卷2》读书笔记(五)}

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


这种技巧有三个问题:

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

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

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

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