线程间同步机制----互斥锁

一、互斥锁通信机制


互斥以排他方式防止共享数据被并发修改。互斥量从本质来说是一把锁,是一个二元变量,其状态为开锁(允许0)和上锁(禁止1),在访问共享资源前对互斥量进行设置(加锁),在访问完成后释放(解锁)互斥量。

(1)在访问该资源前,首先申请该互斥锁,如果该互斥锁处于开锁状态,则申请到该锁对象,并立即占有该锁(使该锁处于锁定状态),以防止其他线程访问该资源;如果该互斥量处于锁定状态,默认阻塞等待

(2)只有锁定该互斥锁的进程才能释放该互斥锁。其他线程的释放操作无效。


二、互斥锁基本操作


1、初始化和销毁互斥锁


在使用互斥锁之前,需要定义该互斥锁(全局变量)。


pthread_mutex_t lock;

#include  
int  pthread_mutex_init(pthread_mutex_t  *restrict  mutex, const pthread_mutexattr_t  *restrict  attr);
int  pthread_mutex_destory(pthread_mutex_t  *mutex);
//两个函数的返回值:若成功,返回0;否则,返回错误编号


初始化:
第一个参数mutex是指向要初始化的互斥锁的指针。

第二个参数mutexattr是指向属性对象的指针,该属性对象定义要初始化的互斥锁的属性。如果该指针为NULL,则使用默认属性。


此外,还可以使用宏PTHREAD_MUTEX_INITIALIZER初始化静态分配的互斥锁。

#define  PTHREAD_MUTEX_INITIALIZER  { { 0, }}
对于静态初始化的互斥锁,不需要调用pthread_mutex_init()函数。

pthread_mutex_t_mp = PTHREAD_MUTEX_INITIALIZER;


2、申请互斥锁


如果一个线程要占有一共享资源,其必须先给互斥锁上锁。pthread_mutex_lock()函数以阻塞方式申请互斥锁。

#include  
int  pthread_mutex_lock(pthread_mutex_t  *mutex); 	//若成功,返回0;否则,返回错误编号

pthread_mutex_trylock()函数以非阻塞方式申请互斥锁。

#include  
int  pthread_mutex_trylock(pthread_mutex_t  *mutex);	//若成功,返回0;否则,返回错误编号 


如果线程不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住的状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞直接返回0,如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况EBUSY。


3、释放互斥锁


#include 
int  pthread_mutex_unlock(pthread_mutex_t  *mutex);  	//若成功,返回0;否则,返回错误编号

参数mutex为指向要解锁的互斥锁的指针。释放操作只能由占有该互斥锁的线程完成。


三、互斥锁应用实例


下面是一个使用互斥锁的应用实例,在此程序中,共用两个线程: 一个线程负责从标准输入设备中读取数据存储在全局数据区,另一个线程负责将读入的数据输出到标准输出设备。

(1)处理输入操作的线程在接收用户输入信息时不能被中断,因此需要先使用互斥锁获得资源占用,阻塞其他线程的执行。

(2)输出线程中为了保证输出不被中断,同样在输出信息前后需要先锁定互斥锁,操作完成后释放互斥锁。


#include 
#include 
#include 
#include 
#include 

#define WORK_SIZE 1024

void *thread_function(void *arg);
pthread_mutex_t work_mutex;		//全局互斥锁对象
char work_area[WORK_SIZE];		//全局共享数据区
int time_to_exit = 0;

int main(int argc, char *argv[])
{
	pthread_t a_thread;
	int res;
	void *thread_result;

	res = pthread_mutex_init(&work_mutex, NULL);	//初始化互斥量
	if (res != 0)
	{
		printf("Mutex initialization failed");
		exit(EXIT_FAILURE);
	}

	res = pthread_create(&a_thread, NULL, (void *)thread_function, NULL);	//创建新线程
	if (res != 0)
	{
		printf("Thread creation failed");
		exit(EXIT_FAILURE);
	}
	
	pthread_mutex_lock(&work_mutex);	//接收输入前,给互斥锁上锁
	printf("Input some text. Enter 'end' to finish\n");
	while(!time_to_exit)				//time_to_exit值由另一线程修改
	{
		fgets(work_area, WORK_SIZE, stdin);	//从stdin读取到一行信息
		pthread_mutex_unlock(&work_mutex);	//解锁,两个线程抢占互斥量
		while(1)
		{
			pthread_mutex_lock(&work_mutex);	//上锁
			if (work_area[0] != '\0')	//检查读入的内容输出没有
			{						//输出线程将信息输出后将设置work_area[0]!='\0'
				pthread_mutex_unlock(&work_mutex);	//如果没有输出,解锁
				sleep(1);
			}
			else						//如果已经输出,执行下一轮读入
				break;
		}
	}
	pthread_mutex_unlock(&work_mutex);	//解锁
	printf("\nWaiting for thread to finish...\n");
	res = pthread_join(a_thread, &thread_result);	//等待另一个线程结束
	if (res != 0)
	{
		printf("Thread join failed");
		exit(EXIT_FAILURE);
	}
	printf("Thread joined\n");
	pthread_mutex_destroy(&work_mutex);	//销毁互斥锁
	exit(EXIT_FAILURE);
}
void *thread_function(void *arg)	//子线程执行的程序
{
	sleep(1);
	pthread_mutex_lock(&work_mutex);	//上锁,抢占资源
	while(strncmp("end", work_area, 3) != 0)	//判断是否为结束信息end
	{
		printf("You input %d characters\n", strlen(work_area) - 1);	//输出输入的字符个数
		printf("the characters is %s", work_area);	//输出输入的字符内容
		work_area[0] = '\0';		//设置最后1位为'\0',标识已经输出
		pthread_mutex_unlock(&work_mutex);	//解锁
		sleep(1);
		pthread_mutex_lock(&work_mutex);	//上锁
		while (work_area[0] == '\0')	//判断第一位是否为'\0',如果为'\0',标识主线程还没有输入数据
		{								//如果不为'\0',则表示有输入,执行下一轮输出操作
			pthread_mutex_unlock(&work_mutex);	//解锁,等待
			sleep(1);
			pthread_mutex_lock(&work_mutex);	//上锁,再次返回判断
		}
	}
	time_to_exit = 1;			//置结束标识位,通知主线程操作结束
	work_area[0] = '\0';
	pthread_mutex_unlock(&work_mutex);	//解锁
	pthread_exit(0);	//退出
}


undefined reference to 'pthread_create'
undefined reference to 'pthread_join'

问题原因:
    pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,需要链接该库。

问题解决:
    在编译中要加 -lpthread参数
    gcc  mutex_example  mutex_example.c  -lpthread
   mutex_example.c为你些的源文件,不要忘了加上头文件#include


你可能感兴趣的:(linux)