#include<sys/select.h>intselect(intn,fd_set*fdset,NULL,NULL,NULL);// Returns: nonzero count of ready descriptors, −1 on error// Macros for manipulating descriptor setsFD_ZERO(fd_set*fdset);/* Clear all bits in fdset */FD_CLR(intfd,fd_set*fdset);/* Clear bit fd in fdset */FD_SET(intfd,fd_set*fdset);/* Turn on bit fd in fdset */FD_ISSET(intfd,fd_set*fdset);/* Is bit fd in fdset on? */
#include"csapp.h"typedefstruct{/* represents a pool of connected descriptors */intmaxfd;/* largest descriptor in read_set */fd_setread_set;/* set of all active descriptors */fd_setready_set;/* subset of descriptors ready for reading */intnready;/* number of ready descriptors from select */intmaxi;/* highwater index into client array */intclientfd[FD_SETSIZE];/* set of active descriptors */rio_tclientrio[FD_SETSIZE];/* set of active read buffers */}pool;intbyte_cnt=0;/* counts total bytes received by server */intmain(intargc,char**argv){intlistenfd,connfd;socklen_tclientlen;structsockaddr_storageclientaddr;staticpoolpool;if(argc!=2){fprintf(stderr,"usage: %s <port>\n",argv[0]);exit(0);}listenfd=Open_listenfd(argv[1]);init_pool(listenfd,&pool);while(1){/* Wait for listening/connected descriptor(s) to become ready */pool.ready_set=pool.read_set;pool.nready=Select(pool.maxfd+1,&pool.ready_set,NULL,NULL,NULL);/* If listening descriptor ready, add new client to pool */if(FD_ISSET(listenfd,&pool.ready_set)){clientlen=sizeof(structsockaddr_storage);connfd=Accept(listenfd,(SA*)&clientaddr,&clientlen);add_client(connfd,&pool);}/* Echo a text line from each ready connected descriptor */check_clients(&pool);}}
voidinit_pool(intlistenfd,pool*p){/* Initially, there are no connected descriptors */inti;p->maxi=-1;for(i=0;i<FD_SETSIZE;i++)p->clientfd[i]=-1;/* Initially, listenfd is only member of select read set */p->maxfd=listenfd;FD_ZERO(&p->read_set);FD_SET(listenfd,&p->read_set);}
voidadd_client(intconnfd,pool*p){inti;p->nready--;for(i=0;i<FD_SETSIZE;i++)/* Find an available slot */if(p->clientfd[i]<0){/* Add connected descriptor to the pool */p->clientfd[i]=connfd;Rio_readinitb(&p->clientrio[i],connfd);/* Add the descriptor to descriptor set */FD_SET(connfd,&p->read_set);/* Update max descriptor and pool highwater mark */if(connfd>p->maxfd)p->maxfd=connfd;if(i>p->maxi)p->maxi=i;break;}if(i==FD_SETSIZE)/* Couldn't find an empty slot */app_error("add_client error: Too many clients");}
voidcheck_clients(pool*p){inti,connfd,n;charbuf[MAXLINE];rio_trio;for(i=0;(i<=p->maxi)&&(p->nready>0);i++){connfd=p->clientfd[i];rio=p->clientrio[i];/* If the descriptor is ready, echo a text line from it */if((connfd>0)&&(FD_ISSET(connfd,&p->ready_set))){p->nready--;if((n=Rio_readlineb(&rio,buf,MAXLINE))!=0){byte_cnt+=n;printf("Server received %d (%d total) bytes on fd %d\n",n,byte_cnt,connfd);Rio_writen(connfd,buf,n);}/* EOF detected, remove descriptor from pool */else{Close(connfd);FD_CLR(connfd,&p->read_set);p->clientfd[i]=-1;}}}}
#include<pthread.h>typedefvoid*(func)(void*);intpthread_create(pthread_t*tid,pthread_attr_t*attr,func*f,void*arg);// Returns: 0 if OK, nonzero on error
#include"csapp.h"#define N 2void*thread(void*vargp);char**ptr;/* global variable */intmain(){inti;pthread_ttid;char*msgs[N]={"Hello from foo","Hello from bar"};ptr=msgs;for(i=0;i<N;i++)Pthread_create(&tid,NULL,thread,(void*)i);Pthread_exit(NULL);}void*thread(void*vargp){intmyid=(int)vargp;staticintcnt=0;printf("[%d]: %s (cnt=%d)\n",myid,ptr[myid],++cnt);returnNULL;}
; i in %rax, niters in %rcx, cnt in %rdxmovq(%rdi),%rcxtestq%rcx,%rcxjle.L2movl$0,%eax.L3:movqcnt(%rip),%rdxaddq$1,%rdxmovqmovq%rdx,cnt(%rip)addq$1,%raxcmpq%rcx,%raxjne.L3.L2:
typedefstruct{int*buf;/* Buffer array */intn;/* Maximum number of slots */intfront;/* buf[(front+1)%n] is first item */intrear;/* buf[rear%n] is last item */sem_tmutex;/* Protects accesses to buf */sem_tslots;/* Counts available slots */sem_titems;/* Counts available items */}sbuf_t;
所有项目均存储在一个动态分配且包含 n 个空位的整型数组buf中,front和rear用于记录数组中的第一个项目和最后一个项目。信号量mutex实现了对缓冲区访问的互斥,slots和items则分别计算缓冲区中的空位和可用项目的数量。
#include"csapp.h"#include"sbuf.h"/* Create an empty, bounded, shared FIFO buffer with n slots */voidsbuf_init(sbuf_t*sp,intn){sp->buf=Calloc(n,sizeof(int));sp->n=n;/* Buffer holds max of n items */sp->front=sp->rear=0;/* Empty buffer iff front == rear */Sem_init(&sp->mutex,0,1);/* Binary semaphore for locking */Sem_init(&sp->slots,0,n);/* Initially, buf has n empty slots */Sem_init(&sp->items,0,0);/* Initially, buf has zero data items */}/* Clean up buffer sp */voidsbuf_deinit(sbuf_t*sp){Free(sp->buf);}/* Insert item onto the rear of shared buffer sp */voidsbuf_insert(sbuf_t*sp,intitem){P(&sp->slots);/* Wait for available slot */P(&sp->mutex);/* Lock the buffer */sp->buf[(++sp->rear)%(sp->n)]=item;/* Insert the item */V(&sp->mutex);/* Unlock the buffer */V(&sp->items);/* Announce available item */}/* Remove and return the first item from buffer sp */intsbuf_remove(sbuf_t*sp){intitem;P(&sp->items);/* Wait for available item */P(&sp->mutex);/* Lock the buffer */item=sp->buf[(++sp->front)%(sp->n)];/* Remove the item */V(&sp->mutex);/* Unlock the buffer */V(&sp->slots);/* Announce available slot */returnitem;}
#include"csapp.h"staticintbyte_cnt;/* byte counter */staticsem_tmutex;/* and the mutex that protects it */staticvoidinit_echo_cnt(void){Sem_init(&mutex,0,1);byte_cnt=0;}voidecho_cnt(intconnfd){intn;charbuf[MAXLINE];rio_trio;staticpthread_once_tonce=PTHREAD_ONCE_INIT;Pthread_once(&once,init_echo_cnt);Rio_readinitb(&rio,connfd);while((n=Rio_readlineb(&rio,buf,MAXLINE))!=0){P(&mutex);byte_cnt+=n;printf("server received %d (%d total) bytes on fd %d\n",n,byte_cnt,connfd);V(&mutex);Rio_writen(connfd,buf,n);}}
char*ctime_ts(consttime_t*timep,char*privatep){char*sharedp;P(&mutex);sharedp=ctime(timep);strcpy(privatep,sharedp);/* Copy string from shared to private */V(&mutex);returnprivatep;}
/* rand_r - a reentrant pseudo-random integer on 0..32767 */intrand_r(unsignedint*nextp){*nextp=*nextp*1103515245+12345;return(unsignedint)(*nextp/65536)%32768;}
#include"csapp.h"#define N 4void*thread(void*vargp);intmain(){pthread_ttid[N];inti;for(i=0;i<N;i++)Pthread_create(&tid[i],NULL,thread,&i);for(i=0;i<N;i++)Pthread_join(tid[i],NULL);exit(0);}/* thread routine */void*thread(void*vargp){intmyid=*((int*)vargp);printf("Hello from thread %d\n",myid);returnNULL;}
示例程序中,主线程创建了四个对等线程并将指向了唯一整数 ID 的指针&i传递给它们。对等线程将参数传递的 ID 复制到局部变量(第 21 行),然后打印包含 ID 的消息。该程序看似简单,然而却输出了错误的结果: