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

ExpandedBlockStart.gifContractedBlock.gif/**//*includeglobals*/
None.gif#include
"unpipc.h"
None.gif
None.gif
#defineMAXNITEMS1000000
None.gif
#defineMAXNTHREADS100
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//*globalssharedbythreads*/
ExpandedBlockStart.gifContractedBlock.gif
intnitems;/**//*read-onlybyproducerandconsumer*/
None.gif
intbuff[MAXNITEMS];
ExpandedBlockStart.gifContractedBlock.gif
structdot.gif{
InBlock.gifpthread_mutex_tmutex;
ExpandedSubBlockStart.gifContractedSubBlock.gif
intnput;/**//*nextindextostore*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
intnval;/**//*nextvaluetostore*/
ExpandedBlockStart.gifContractedBlock.gif}
put=dot.gif{PTHREAD_MUTEX_INITIALIZER};
None.gif
ExpandedBlockStart.gifContractedBlock.gif
structdot.gif{
InBlock.gifpthread_mutex_tmutex;
InBlock.gifpthread_cond_tcond;
ExpandedSubBlockStart.gifContractedSubBlock.gif
intnready;/**//*numberreadyforconsumer*/
ExpandedBlockStart.gifContractedBlock.gif}
nready=dot.gif{PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER};
ExpandedBlockStart.gifContractedBlock.gif
/**//*endglobals*/
None.gif
None.gif
void*produce(void*),*consume(void*);
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//*includemain*/
None.gif
int
None.gifmain(
intargc,char**argv)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
inti,nthreads,count[MAXNTHREADS];
InBlock.gifpthread_ttid_produce[MAXNTHREADS],tid_consume;
InBlock.gif
InBlock.gif
if(argc!=3)
InBlock.giferr_quit(
"usage:prodcons6<#items><#threads>");
InBlock.gifnitems
=min(atoi(argv[1]),MAXNITEMS);
InBlock.gifnthreads
=min(atoi(argv[2]),MAXNTHREADS);
InBlock.gif
InBlock.gifSet_concurrency(nthreads
+1);
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4createallproducersandoneconsumer*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
for(i=0;i<nthreads;i++)dot.gif{
InBlock.gifcount[i]
=0;
InBlock.gifPthread_create(
&tid_produce[i],NULL,produce,&count[i]);
ExpandedSubBlockEnd.gif}

InBlock.gifPthread_create(
&tid_consume,NULL,consume,NULL);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*waitforallproducersandtheconsumer*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
for(i=0;i<nthreads;i++)dot.gif{
InBlock.gifPthread_join(tid_produce[i],NULL);
InBlock.gifprintf(
"count[%d]=%d/n",i,count[i]);
ExpandedSubBlockEnd.gif}

InBlock.gifPthread_join(tid_consume,NULL);
InBlock.gif
InBlock.gifexit(
0);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**//*endmain*/
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**//*includeprodcons*/
None.gif
void*
None.gifproduce(
void*arg)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif
for(;;)dot.gif{
InBlock.gifPthread_mutex_lock(
&put.mutex);
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(put.nput>=nitems)dot.gif{
InBlock.gifPthread_mutex_unlock(
&put.mutex);
ExpandedSubBlockStart.gifContractedSubBlock.gif
return(NULL);/**//*arrayisfull,we'redone*/
ExpandedSubBlockEnd.gif}

InBlock.gifbuff[put.nput]
=put.nval;
InBlock.gifput.nput
++;
InBlock.gifput.nval
++;
InBlock.gifPthread_mutex_unlock(
&put.mutex);
InBlock.gif
InBlock.gifPthread_mutex_lock(
&nready.mutex);
InBlock.gif
if(nready.nready==0)
InBlock.gifPthread_cond_signal(
&nready.cond);//发出信号
InBlock.gif
nready.nready++;//置为1
InBlock.gif
Pthread_mutex_unlock(&nready.mutex);
InBlock.gif
InBlock.gif
*((int*)arg)+=1;
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
void*
None.gifconsume(
void*arg)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
inti;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
for(i=0;i<nitems;i++)dot.gif{
InBlock.gifPthread_mutex_lock(
&nready.mutex);
InBlock.gif
while(nready.nready==0)
InBlock.gifPthread_cond_wait(
&nready.cond,&nready.mutex);//wait条件变量
InBlock.gif
nready.nready--;//置为0
InBlock.gif
Pthread_mutex_unlock(&nready.mutex);
InBlock.gif
InBlock.gif
if(buff[i]!=i)
InBlock.gifprintf(
"buff[%d]=%d/n",i,buff[i]);
ExpandedSubBlockEnd.gif}

InBlock.gif
return(NULL);
ExpandedBlockEnd.gif}

ExpandedBlockStart.gifContractedBlock.gif
/**//*endprodcons*/
None.gif

这里在生产者的代码中,当它获取到互斥锁时,若发出信号唤醒消费者,则此时可能系统立即调度唤醒消费者,但互斥锁任然在生产者之手,则消费者获取互斥锁必然失败,为了避免此种低效的情况出现,我们可以直到生产者释放互斥锁后才给与之关联的条件变量发送信号,这在Posix里是可以这么做的,但Posix又接着说:若要可预见的调度行为,则调用pthead_cond_signal的线程必须锁住该互斥锁。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

当在进程间共享互斥锁时,持有该互斥锁的进程可能在持有期间终止,但无法让系统在终止时自动释放掉所持有的锁。一个线程也可以在持有互斥锁期间终止,可能是自己调用pthread_exit或被另一个线程取消,若是前者,则它应该知道自己还有一个互斥锁,若是后者,则该线程可以先安装一个将在被取消时调用的清理处理程序。但最致命的情况是由于此线程的终止导致整个进程的终止。即使一个进程终止时系统自动释放其持有的锁,但也会导致临界区内数据处于不一致状态,

读写锁的规则:

1,只要没有线程持有某个给定的读写锁用于写,则任意数目的线程可以持有

该读写锁用于读


2
,仅当没有线程持有某个给定的读写锁用于读或用于写时,才能分配该读写锁用于写


这种锁在那些读数据比写数据频繁的应用中使用比较有用,允许多个读者提供了更高的并发度,同时在
写者修改数据时保护数据,避免任何其他读者或写者的干扰。

这种对某个给定资源的共享访问也叫共享独占上锁,获取一个读写锁用于读称为共享锁,获取一个读写锁用于写称为独占锁。在操作系统中就介绍过这种,经典的问题就是读者写者问题,有多种类型:多读者,单写者或多读者,多写者。,此外还有要考虑的就是读者和写者谁优先,也就产生了1类和2类读写问题。

读写锁类型为pthread_rwlock_tpthread_rwlock_rdlock获取一个读出锁,若对应的读写锁已经被某个写者持有,则阻塞调用线程,pthread_rwlock_wrlock获取一个写出锁,若对应的读写锁已经被另一个写者持有或被一个或多个读者持有,则阻塞调用线程,pthread_rwlock_unlock释放一个读出锁或写入锁。

使用互斥锁和条件变量实现读写锁(写者优先)

ExpandedBlockStart.gifContractedBlock.giftypedefstructdot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gifpthread_mutex_trw_mutex;
/**//*basiclockonthisstruct*///访问此读写锁使用的互斥锁
ExpandedSubBlockStart.gifContractedSubBlock.gif
pthread_cond_trw_condreaders;/**//*forreaderthreadswaiting读者线程使用*/
ExpandedSubBlockStart.gifContractedSubBlock.gifpthread_cond_trw_condwriters;
/**//*forwriterthreadswaiting写者线程使用*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
intrw_magic;/**//*forerrorchecking初始化成功后,被设置为RW_MAGIC,所有函数测试此成员,检查调用者是否作为参数传递了指向某个已经初始化的读写锁的指针,读写锁摧毁时,被设置为0*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
intrw_nwaitreaders;/**//*thenumberwaiting读者计数器*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
intrw_nwaitwriters;/**//*thenumberwaiting写者计数器*/
InBlock.gif
intrw_refcount;//本读写锁的当前状态,-1表示是写入锁(任意时刻只有一个),0表示可用,大于0表示当前容纳着的读出锁数目
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4-1ifwriterhasthelock,else#readersholdingthelock*/
ExpandedBlockEnd.gif}
pthread_rwlock_t;
None.gif

None.gifintpthread_rwlock_init(pthread_rwlock_t*rw,pthread_rwlockattr_t*attr)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
intresult;
InBlock.gif
InBlock.gif
if(attr!=NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif
return(EINVAL);/**//*notsupported*/
InBlock.gif
InBlock.gif
if((result=pthread_mutex_init(&rw->rw_mutex,NULL))!=0)
InBlock.gif
gotoerr1;
InBlock.gif
if((result=pthread_cond_init(&rw->rw_condreaders,NULL))!=0)
InBlock.gif
gotoerr2;
InBlock.gif
if((result=pthread_cond_init(&rw->rw_condwriters,NULL))!=0)
InBlock.gif
gotoerr3;
InBlock.gifrw
->rw_nwaitreaders=0;
InBlock.gifrw
->rw_nwaitwriters=0;
InBlock.gifrw
->rw_refcount=0;
InBlock.gifrw
->rw_magic=RW_MAGIC;
InBlock.gif
InBlock.gif
return(0);
InBlock.gif
InBlock.giferr3:
InBlock.gifpthread_cond_destroy(
&rw->rw_condreaders);
InBlock.giferr2:
InBlock.gifpthread_mutex_destroy(
&rw->rw_mutex);
InBlock.giferr1:
ExpandedSubBlockStart.gifContractedSubBlock.gif
return(result);/**//*anerrnovalue*/
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_rwlock_destroy(pthread_rwlock_t*rw)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
//检查参数是否有效
InBlock.gif
if(rw->rw_magic!=RW_MAGIC)
InBlock.gif
return(EINVAL);
InBlock.gif
if(rw->rw_refcount!=0||
InBlock.gifrw
->rw_nwaitreaders!=0||rw->rw_nwaitwriters!=0)
InBlock.gif
return(EBUSY);
InBlock.gif
InBlock.gifpthread_mutex_destroy(
&rw->rw_mutex);
InBlock.gifpthread_cond_destroy(
&rw->rw_condreaders);
InBlock.gifpthread_cond_destroy(
&rw->rw_condwriters);
InBlock.gifrw
->rw_magic=0;
InBlock.gif
InBlock.gif
return(0);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_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*/
InBlock.gif
while(rw->rw_refcount<0||rw->rw_nwaitwriters>0)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{//rw_refcount小于0(表示有写者持有读写锁),rw_nwaitwriters大于0表示有线程正等着获取读写锁的一个写入锁,则无法获取该读写锁的一个读出锁
InBlock.gif
rw->rw_nwaitreaders++;
InBlock.gifresult
=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);
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(result);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_rwlock_tryrdlock(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
InBlock.gif
if(rw->rw_refcount<0||rw->rw_nwaitwriters>0)
ExpandedSubBlockStart.gifContractedSubBlock.gifresult
=EBUSY;/**//*heldbyawriterorwaitingwriters*/
InBlock.gif
else
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount++;/**//*incrementcountofreaderlocks*/
InBlock.gif
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(result);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_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))!=0)
InBlock.gif
return(result);
InBlock.gif
InBlock.gif
while(rw->rw_refcount!=0)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{//只要有读者持有读出锁或有一个写者持有唯一的写入锁,调用线程阻塞
InBlock.gif
rw->rw_nwaitwriters++;
InBlock.gifresult
=pthread_cond_wait(&rw->rw_condwriters,&rw->rw_mutex);
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(result);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_rwlock_trywrlock(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
InBlock.gif
if(rw->rw_refcount!=0)
ExpandedSubBlockStart.gifContractedSubBlock.gifresult
=EBUSY;/**//*heldbyeitherwriterorreader(s)*/
InBlock.gif
else
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount=-1;/**//*available,indicateawriterhasit*/
InBlock.gif
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(result);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_rwlock_unlock(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
InBlock.gif
if(rw->rw_refcount>0)
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount--;/**//*releasingareader*/
InBlock.gif
elseif(rw->rw_refcount==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount=0;/**//*releasingareader*/
InBlock.gif
else
InBlock.giferr_dump(
"rw_refcount=%d",rw->rw_refcount);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4givepreferencetowaitingwritersoverwaitingreaders*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(rw->rw_nwaitwriters>0)dot.gif{
InBlock.gif
if(rw->rw_refcount==0)
InBlock.gifresult
=pthread_cond_signal(&rw->rw_condwriters);
ExpandedSubBlockEnd.gif}
elseif(rw->rw_nwaitreaders>0)
InBlock.gifresult
=pthread_cond_broadcast(&rw->rw_condreaders);
InBlock.gif
InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(result);
ExpandedBlockEnd.gif}

None.gif

None.gifintpthread_rwlock_unlock(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
InBlock.gif
if(rw->rw_refcount>0)
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount--;/**//*releasingareader*/
InBlock.gif
elseif(rw->rw_refcount==-1)
ExpandedSubBlockStart.gifContractedSubBlock.gifrw
->rw_refcount=0;/**//*releasingawriter*/
InBlock.gif
else
InBlock.giferr_dump(
"rw_refcount=%d",rw->rw_refcount);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*4givepreferencetowaitingwritersoverwaitingreaders*/
InBlock.gif
//写者优先,而只有一个写者
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(rw->rw_nwaitwriters>0)dot.gif{
InBlock.gif
if(rw->rw_refcount==0)
InBlock.gifresult
=pthread_cond_signal(&rw->rw_condwriters);//通知等待的那个写者
ExpandedSubBlockEnd.gif
}
elseif(rw->rw_nwaitreaders>0)
InBlock.gifresult
=pthread_cond_broadcast(&rw->rw_condreaders);//通知所有等待的读者
InBlock.gif

InBlock.gifpthread_mutex_unlock(
&rw->rw_mutex);
InBlock.gif
return(result);
ExpandedBlockEnd.gif}

None.gif

这里的读出锁和写入锁函数都有一个问题,若调用线程阻塞在pthread_cond_wati调用上,并且随后此线程被取消了,则它会在还持有互斥锁的情况下终止,于是rw_nwaitreaders计数器的值会出错

阅读更多
想对作者说点什么?

博主推荐

换一批

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