`

linux c学习笔记----线程同步

阅读更多

1.互斥量


互斥变量用pthead_mutex_t数据类型来表示,在使用互斥变量之前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以能过调用pthread_mutex_init函数进行初始化。如果动态地分配互斥量(例如通过调用malloc)函数,那么释放内存前需要使用pthread_mutex_destroy.


int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexarrt_t * restrict arrt);

int pthread_mutex_destroy(pthread_mutex_t &mutex);

返回值:成功返回0,否则返回错误编号。

要用默认的属性初始化互斥量,只需把attr设置为NULL。


int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:成功返回0,否则返回错误编号。



#include <stdlib.h>
#include <pthread.h>

struct foo {
	int             f_count;
	pthread_mutex_t f_lock;
	/* ... more stuff here ... */
};

struct foo *
foo_alloc(void) /* allocate the object */
{
	struct foo *fp;

	if ((fp = malloc(sizeof(struct foo))) != NULL) {
		fp->f_count = 1;
		if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
			free(fp);
			return(NULL);
		}
		/* ... continue initialization ... */
	}
	return(fp);
}

void
foo_hold(struct foo *fp) /* add a reference to the object */
{
	pthread_mutex_lock(&fp->f_lock);
	fp->f_count++;
	pthread_mutex_unlock(&fp->f_lock);
}

void
foo_rele(struct foo *fp) /* release a reference to the object */
{
	pthread_mutex_lock(&fp->f_lock);
	if (--fp->f_count == 0) { /* last reference */
		pthread_mutex_unlock(&fp->f_lock);
		pthread_mutex_destroy(&fp->f_lock);
		free(fp);
	} else {
		pthread_mutex_unlock(&fp->f_lock);
	}
}

 2.避免死锁

如果线程试图对同一个互斥量加锁两次,那么它自身就会陷入死锁状态。

一个线程试图以与另一个线程相反的顺序销售互斥量时,才可能出现死锁。

实例:



#include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   #include <pthread.h>
   #include <errno.h>
   pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
   int lock_var;
   time_t end_time;
   void pthread1(void *arg);
   void pthread2(void *arg);
   int main(int argc, char *argv[])
  {
    pthread_t id1,id2;
    pthread_t mon_th_id;
    int ret;
    end_time = time(NULL)+10;
   /*互斥锁初始化*/
     pthread_mutex_init(&mutex,NULL);
   /*创建两个线程*/
     ret=pthread_create(&id1,NULL,(void *)pthread1, NULL);
     if(ret!=0)
     perror("pthread cread1");
     ret=pthread_create(&id2,NULL,(void *)pthread2, NULL);
     if(ret!=0)
     perror("pthread cread2");
     pthread_join(id1,NULL);                                 
     pthread_join(id2,NULL);                                 
     exit(0);                                                
   }
                                                          
   void pthread1(void *arg)                                
   {                                                       
    int i;                                                  
    while(time(NULL) < end_time)
    {                           
    /*互斥锁上锁*/                                          
     if(pthread_mutex_lock(&mutex)!=0)
     {                      
      perror("pthread_mutex_lock");                           
     }                                                       
     else                                                    
     printf("pthread1:pthread1 lock the variable\n");        
     for(i=0;i<2;i++){                                       
     sleep(1);                                               
     lock_var++;                                             
     }                                                       
   /*互斥锁接锁*/                                          
     if(pthread_mutex_unlock(&mutex)!=0){                    
     perror("pthread_mutex_unlock");                         
     }                                                       
     else                                                    
     printf("pthread1:pthread1 unlock the variable\n");      
     sleep(1);                                               
    }                                                       
   }                                                       
   void pthread2(void *arg)                                
   {                                                       
    int nolock=0;                                           
    int ret;                                                
    while(time(NULL) < end_time)
    {                           
     /*测试互斥锁*/                                          
     ret=pthread_mutex_trylock(&mutex);                      
     if(ret==EBUSY)                                          
     printf("pthread2:the variable is locked by pthread1\n");
     else
     {   
      if(ret!=0)
      {                                                                                       
        perror("pthread_mutex_trylock");                  
        exit(1);                                          
       }                                                 
       else                                              
       printf("pthread2:pthread2 got lock.The variable is%d\n",lock_var);                                  
               /*互斥锁接锁*/                                    
       if(pthread_mutex_unlock(&mutex)!=0)
       {              
        perror("pthread_mutex_unlock");                   
       }                                                 
       else                                              
       printf("pthread2:pthread2 unlock the variable\n");
      }                                                 
     sleep(3);                                         
     }                                                 
    } 


 3.读写锁

1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)


int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);

初始化读/写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

锁定读/写锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

读取读/写锁上的锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

写读/写锁上的锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

解除读/写锁

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

成功返回0,否则返回错误编号

实例:

 

#include <stdlib.h>
#include <pthread.h>

struct job {
	struct job *j_next;
	struct job *j_prev;
	pthread_t   j_id;   /* tells which thread handles this job */
	/* ... more stuff here ... */
};

struct queue {
	struct job      *q_head;
	struct job      *q_tail;
	pthread_rwlock_t q_lock;
};

/*
 * Initialize a queue.
 */
int
queue_init(struct queue *qp)
{
	int err;

	qp->q_head = NULL;
	qp->q_tail = NULL;
	err = pthread_rwlock_init(&qp->q_lock, NULL);
	if (err != 0)
		return(err);

	/* ... continue initialization ... */

	return(0);
}

/*
 * Insert a job at the head of the queue.
 */
void
job_insert(struct queue *qp, struct job *jp)
{
	pthread_rwlock_wrlock(&qp->q_lock);
	jp->j_next = qp->q_head;
	jp->j_prev = NULL;
	if (qp->q_head != NULL)
		qp->q_head->j_prev = jp;
	else
		qp->q_tail = jp;	/* list was empty */
	qp->q_head = jp;
	pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * Append a job on the tail of the queue.
 */
void
job_append(struct queue *qp, struct job *jp)
{
	pthread_rwlock_wrlock(&qp->q_lock);
	jp->j_next = NULL;
	jp->j_prev = qp->q_tail;
	if (qp->q_tail != NULL)
		qp->q_tail->j_next = jp;
	else
		qp->q_head = jp;	/* list was empty */
	qp->q_tail = jp;
	pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * Remove the given job from a queue.
 */
void
job_remove(struct queue *qp, struct job *jp)
{
	pthread_rwlock_wrlock(&qp->q_lock);
	if (jp == qp->q_head) {
		qp->q_head = jp->j_next;
		if (qp->q_tail == jp)
			qp->q_tail = NULL;
	} else if (jp == qp->q_tail) {
		qp->q_tail = jp->j_prev;
		if (qp->q_head == jp)
			qp->q_head = NULL;
	} else {
		jp->j_prev->j_next = jp->j_next;
		jp->j_next->j_prev = jp->j_prev;
	}
	pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * Find a job for the given thread ID.
 */
struct job *
job_find(struct queue *qp, pthread_t id)
{
	struct job *jp;

	if (pthread_rwlock_rdlock(&qp->q_lock) != 0)
		return(NULL);

	for (jp = qp->q_head; jp != NULL; jp = jp->j_next)
		if (pthread_equal(jp->j_id, id))
			break;

	pthread_rwlock_unlock(&qp->q_lock);
	return(jp);
}

 

 

这个例子中,不管什么时候需要增加一个作业也不能队列中或者从队列中删除作业,都用写模式锁住队列的读写锁。不管何时搜索队列,首先需要获取读模式下的锁,允许所有的工作线程并发地搜索队列。在这种情况下,只有线程搜索队列的频率远远高于增加或者删除作业时,使用读写锁才可能改善性能。



4.条件变量

 

条件变量是线程可用的另一种同步机制。通常和互斥量一起使用,允许线程以无竞争的方式等待特定条件发生。条件本身由互斥信号量保护,线程在改变条件状态之前必须首先锁住信号量,在获得信号量之前不会察觉到这种改变。

    条件变量在使用之前要初始化。动态分配的可以由pthread_cond_init函数来分配,静态变量可以直接将PTHREAD_COND_INITIALIZER赋给静态分配的条件。动态分配的变量需要使用pthread_mutex_destory来去初始化,然后再free。

静态创建:pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
动态创建:pthread_cond _t cond;
  pthread_cond_init(&cond,NULL);

其中的第二个参数NULL表示条件变量的属性,虽然POSIX中定义了条件变量的属性,但在LinuxThread中并没有实现,因此常常忽略

int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
                      pthread_mutex_t *restrict mutex,
                      const strcut timespec *restrict timeout);
/*若成功则返回真,错误则返回错误编号*/
传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的信号量传给函数,函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁。这个是原子操作,当它返回时,互斥量会被再次锁住。
pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数相似。只是多了一个timeout。timeout变量指定了等待的时间。时间的结构:
struct timespec{
time_t tv_sec; /*seconds*/
long tv_nsec; /*nanoseconds*/
}
int pthread_cond_signal(pthread_cond_t *cond); /*唤醒等待该条件的某个进程*/
int pthread_cond_broadcast(pthread_cond_t *cond); /*唤醒等待该条件的所有进程*/
要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。函数pthread_cond_broadcast(pthread_cond_t *cond)用来唤醒所有被阻塞在条件变量cond上的线程。这些线程被唤醒后将再次竞争相应的互斥锁,所以必须小心使用这个函数。

 

实例:

 

#include<stdio.h>
#include<pthread.h>

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
int count=5;

void *decrement(void *arg)
{
while(1)
{
    pthread_mutex_lock(&mutex);
    while(count<=0)
    {
        printf("count<=0,thread1 is hanging!\n");
        pthread_cond_wait(&cond,&mutex);
        sleep(1);
        printf("sleep!\n");
    }
    count=count-1;
    pthread_mutex_unlock(&mutex);    

    if(count==9)
    {
        printf("count=9,thread1 is over!\n");
        return NULL;
    }
}

}

void *increment(void *arg)
{sleep(1);
while(1)
{
    pthread_mutex_lock(&mutex);
    count=count+1;
    if(count>0)
    {
        printf("count=%d,change cond state!\n",count);
        pthread_cond_signal(&cond);
    }
    pthread_mutex_unlock(&mutex);

    if(count==10)
    {
        printf("count=10,thread2 is over!\n");
        return NULL;
    }
}

}

int main()
{
    int i1=1,i2=1;
    pthread_t id1,id2;
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    pthread_create(&id1,NULL,decrement,NULL);
    pthread_create(&id2,NULL,increment,NULL);
    
    i2=pthread_join(id2,NULL);
    i1=pthread_join(id1,NULL);
    if((i2==0)&&(i1==0))
    {
        printf("count=%d,the main thread!\n",count);
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mutex);
        return 0;
    }
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics