Linux系统编程之常用线程同步的三种方法

Linux系统编程之线程同步高效率编程

         ~~~~~~~~         Linux系统中线程最大的特点就是共享性,线程同步问题较为困难也很重要,最常用的三种是:条件变量、互斥锁、无名信号量。(ps: 有名信号量可用于进程同步,无名信号量只能用于线程同步,是轻量级的。)


(一)、【互斥锁】:mutex

线程互斥量数据类型:pthread_mutex_t

  1. 初始化锁
    静态分配: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    动态分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
             ~~~~~~~~          参数一:创建的互斥锁
             ~~~~~~~~          参数二:存储互斥锁信息的结构,一般为NULL

  2. 加锁:对共享资源的访问,要对互斥量进行加锁,如果互斥量已经上了锁,调用线程会阻塞,直到互斥量被解锁。
    int pthread_mutex_lock(pthread_mutex *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex);
             ~~~~~~~~         参数:指明互斥锁

  3. 解锁:在完成了对共享资源的访问后,要对互斥量进行解锁
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
             ~~~~~~~~         参数:指明互斥锁

  4. 销毁锁
    int pthread_mutex_destroy(pthread_mutex *mutex);
             ~~~~~~~~         参数:指明互斥锁


(二)、【条件变量】:cond

         ~~~~~~~~         条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
数据类型:pthread_cond_t

  1. 初始化
    静态:pthread_cond_t cond = PTHREAD_COND_INITIALIER;
    动态:int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
             ~~~~~~~~         参数一:指明条件变量
             ~~~~~~~~         参数二:存储条件变量属性的结构>
             ~~~~~~~~         
  2. 等待条件成立:释放锁,同时等待条件为真才能有停止阻塞。
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
             ~~~~~~~~         参数一:指明条件变量
             ~~~~~~~~         参数二:指明互斥锁
    int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
             ~~~~~~~~         
  3. 激活条件变量:
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞
      ~  
  4. 注销条件变量
    int pthread_cond_destroy(pthread_cond_t *cond);

(三)、【无名信号量】:sem

注意:链接需要加上-pthread选项
例如:gcc -pthread main.c -o main
  ~  
         ~~~~~~~~         有名信号量可用于进程的同步,头文件:#include;而无名信号量只能用于线程,是轻量级,头文件:#include )

  1. 初始化:
    int sem_init (sem_t *sem , int pshared, unsigned int value);
             ~~~~~~~~         参数一:指明信号量
             ~~~~~~~~         参数二:共享选项(linux 只支持为0,即表示它是当前进程的局部信号量)
             ~~~~~~~~         参数三:设置初始值
             ~~~~~~~~         
  2. 等待信号量:给信号量减1,然后等待直到信号量的值大于0。
    int sem_wait(sem_t *sem);
      ~  
  3. 释放信号量:
    int sem_post(sem_t *sem);
      ~  
  4. 销毁信号量:
    int sem_destroy(sem_t *sem);

【DEMO】

         ~~~~~~~~         现有两个同学打扫卫生,学生A负责扫地,学生B负责拖地,很明显要扫完地之后在拖地,由此引入线程同步。

1、条件变量和互斥锁的联合利用实现
#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG_INFO(...) printf("Info: "); printf(__VA_ARGS__)

void *student_1();
void *student_2();


int num = 0;	//共享资源
pthread_mutex_t mulock = PTHREAD_MUTEX_INITIALIZER;		//互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;			//条件变量
pthread_t stu_thread[2];		//两个学生线程
int main()
{
	int i;
	
	// 创建两个学生线程
	pthread_create(&stu_thread[0], NULL, student_1, NULL);
	pthread_create(&stu_thread[1], NULL, student_2, NULL);
	
	// 等待两个线程结束
	for(i=0; i<2; i++)
	{
		pthread_join(stu_thread[i], NULL);
	}
	
	// 注销操作
	pthread_mutex_destroy(&mulock);
	pthread_cond_destroy(&cond);
	return 0;
}

void *student_1()
{
	int i;
	DEBUG_INFO("student a start work .\n");
	
	for(i=0; i<5; i++)
	{
		DEBUG_INFO("i = %d \n", i);
		pthread_mutex_lock(&mulock);	//锁住
		num++;		//扫一次地
		if(num >= 5)
		{
			DEBUG_INFO("student a finished work .\n");
			pthread_cond_signal(&cond);	//通知学生B已经扫完地了,并解锁
		}
		
		pthread_mutex_unlock(&mulock);
		sleep(1);
	}
	
	pthread_exit(NULL);
	return 0;
}
void *student_2()
{
	DEBUG_INFO("in student 2 .. \n");
	while(num < 5)		//不用if四因为需要防止莫名错误
	{
		pthread_cond_wait(&cond, &mulock);	//等待学生A扫地结束,等不到会再次一直阻塞
	}
	
	num = 0;	//拖地
	pthread_mutex_unlock(&mulock);
	DEBUG_INFO("student b finished work .\n");
	pthread_exit(NULL);
	return 0;
}


Makefile
Linux系统编程之常用线程同步的三种方法_第1张图片
运行结果
Linux系统编程之常用线程同步的三种方法_第2张图片
         ~~~~~~~~         由运行结果可见,学生A先完成工作,学生B在完成工作,所以成功实现线程同步。

2、信号量实现
/****************************************************************************************
* 文件名: demo2.c
* 创建者: 
* 时 间: 
* 联 系: 
* 简 介: 
*****************************************************************************************/

#include 
#include 
#include 
#include 
#include 
#include 

#define DEBUG_INFO(...) printf("Info: "); printf(__VA_ARGS__)

int num = 0;	//共享资源
sem_t mysem; //用于同步的信号量
pthread_t stu_thread[2];		//两个学生线程

void *student_1();
void *student_2();


int main()
{
	// 初始化信号量
	sem_init(&mysem, 0, 0);
	
	int i;
	
	// 创建两个学生线程
	pthread_create(&stu_thread[0], NULL, student_1, NULL);
	pthread_create(&stu_thread[1], NULL, student_2, NULL);
	
	// 等待两个线程结束
	for(i=0; i<2; i++)
	{
		pthread_join(stu_thread[i], NULL);
	}
	
	// 注销操作
	sem_destroy(&mysem);
	return 0;
}


void *student_1()
{
	int i;
	DEBUG_INFO("student a start work .\n");
	
	for(i=0; i<5; i++)
	{
		DEBUG_INFO("i = %d \n", i);
		num++;		//扫一次地
		if(num >= 5)
		{
			DEBUG_INFO("student a finished work .\n");
			sem_post(&mysem);	//释放信号量
		}
		
		sleep(1);
	}
	
	pthread_exit(NULL);
	return 0;
}
void *student_2()
{
	DEBUG_INFO("in student 2 .. \n");
	sem_wait(&mysem);		//等待信号量	
	num = 0;	//拖地
	DEBUG_INFO("student b finished work .\n");
	pthread_exit(NULL);
	return 0;
}


【运行结果】
Linux系统编程之常用线程同步的三种方法_第3张图片
         ~~~~~~~~         由运行结果可见,用信号量的程序运行结果与使用条件变量结果一致,所以实验成功!


end…

你可能感兴趣的:(Linux,信号量,互斥锁,条件变量,线程同步)