typedefstruct__counter_t{intglobal;// global count
pthread_mutex_tglock;// global lock
intlocal[NUMCPUS];// local count (per cpu)
pthread_mutex_tllock[NUMCPUS];// ... and locks
intthreshold;// update frequency
}counter_t;// init: record threshold, init locks, init values
// of all local counts and global count
voidinit(counter_t*c,intthreshold){c->threshold=threshold;c->global=0;pthread_mutex_init(&c->glock,NULL);inti;for(i=0;i<NUMCPUS;i++){c->local[i]=0;pthread_mutex_init(&c->llock[i],NULL);}}// update: usually, just grab local lock and update local amount
// once local count has risen by ’threshold’, grab global
// lock and transfer local values to it
voidupdate(counter_t*c,intthreadID,intamt){intcpu=threadID%NUMCPUS;pthread_mutex_lock(&c->llock[cpu]);c->local[cpu]+=amt;// assumes amt > 0
if(c->local[cpu]>=c->threshold){// transfer to global
pthread_mutex_lock(&c->glock);c->global+=c->local[cpu];pthread_mutex_unlock(&c->glock);c->local[cpu]=0;}pthread_mutex_unlock(&c->llock[cpu]);}// get: just return global amount (which may not be perfect)
intget(counter_t*c){pthread_mutex_lock(&c->glock);intval=c->global;pthread_mutex_unlock(&c->glock);returnval;// only approximate!
}
typedefstruct__node_t{intvalue;struct__node_t*next;}node_t;typedefstruct__queue_t{node_t*head;node_t*tail;pthread_mutex_theadLock;// Mutex for head pointer
pthread_mutex_ttailLock;// Mutex for tail pointer
}queue_t;// Initialize the queue
voidQueue_Init(queue_t*q){// Allocate memory for a dummy node to represent the head of the queue
node_t*tmp=malloc(sizeof(node_t));tmp->next=NULL;// Initialize the head and tail pointers to the dummy node
q->head=q->tail=tmp;// Initialize mutexes for head and tail pointers
pthread_mutex_init(&q->headLock,NULL);pthread_mutex_init(&q->tailLock,NULL);}// Enqueue an element into the queue
voidQueue_Enqueue(queue_t*q,intvalue){// Allocate memory for the new node
node_t*tmp=malloc(sizeof(node_t));assert(tmp!=NULL);tmp->value=value;tmp->next=NULL;// Acquire the tailLock mutex
pthread_mutex_lock(&q->tailLock);// Insert the new node after the current tail node
q->tail->next=tmp;// Update the tail pointer to point to the new node
q->tail=tmp;// Release the tailLock mutex
pthread_mutex_unlock(&q->tailLock);}// Dequeue an element from the queue
intQueue_Dequeue(queue_t*q,int*value){// Acquire the headLock mutex
pthread_mutex_lock(&q->headLock);// Get the current head node
node_t*tmp=q->head;// Get the next node after the head
node_t*newHead=tmp->next;// If the queue is empty (newHead is NULL), release the headLock mutex and return -1
if(newHead==NULL){pthread_mutex_unlock(&q->headLock);return-1;// queue was empty
}// Extract the value from the node to be dequeued
*value=newHead->value;// Update the head pointer to point to the next node
q->head=newHead;// Release the headLock mutex
pthread_mutex_unlock(&q->headLock);// Free the memory of the dequeued node
free(tmp);// Return 0 indicating successful dequeue operation
return0;}
在向多处理器过渡之初,许多操作系统都使用单锁,包括 Sun OS 和 Linux。在后者中,这种锁甚至有一个名字,即大内核锁(BKL)。多年来,这种简单的方法一直很好,但当多 CPU 系统成为常态时,内核中每次只允许一个活动线程就成了性能瓶颈。因此,终于到了为这些系统添加改进并发性优化的时候了。在 Linux 系统中,采用了更直接的方法:用多个锁代替一个锁。而在 Sun 内部,则做出了一个更激进的决定:建立一个全新的操作系统,即 Solaris,从一开始就从根本上融入并发性。