进行多线程编程,因为无法知道哪个线程会在哪个时候对共享资源进行操作,因此让如何保护共享资源变得复杂,通过下面这些技术的使用,可以解决
线程之间对资源的竞争:
1. 互斥量Mutex
2. 信号灯Semaphore
3. 条件变量Conditions
mutex互斥锁线程控制
1、互斥锁是用一种简单的加锁方法来控制对共享资源的原子操作。
2、互斥锁只有两种状态,也就是上锁和解锁,可以把互斥锁看作某种意义上的全局变量。
3、在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作。若其他线程希望上锁一个已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。
互斥锁的基本操作:
一、互斥锁初始化:pthread_mutex_init()
函数的作用:初始化互斥锁
函数的原型:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexaddr *attr);
函数的参数:mutex:互斥锁;
mutexattr:PTHREAD_MUTEX_INITIALIZER:快速互斥锁;
返回值:成功为0;出错<0;
二、互斥锁上锁:pthread_mutex_lock()
函数的作用:对互斥锁上锁;
函数的原型:pthread_mutex_lock(pthread_mutex_t *mutex);
返回值:0;出错:-1;
互斥锁判断上锁:pthread_mutex_trylock(pthread_mutex_t *mutex)
互斥锁解锁:pthread_mutex_unlock(pthread_mutex_t *mutex)
消除互斥锁:pthread_mutex_destroy(pthread_mutex_t *mutex)
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
void fun1(void)
{
int i;
pthread_mutex_lock(&mutex);
for(i = 0;i < 5;i++)
{
printf("this is fun1\n");
sleep(1);
}
pthread_mutex_unlock(&mutex);
}
void fun2(void)
{
int i;
pthread_mutex_lock(&mutex);
for(i = 0;i < 5;i++)
{
printf("this is fun2\n");
}
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t id1,id2;
pthread_mutex_init(&mutex,NULL);
pthread_create(&id1,NULL,(void *)fun1,NULL);
pthread_create(&id2,NULL,(void *)fun2,NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
该段程序成功实现了线程1上锁时线程2无法运行,待线程1 完全运行结束后,线程2才继续运行;
信号量线程控制
信号量也就是操作系统中所用到的PV原子操作,它广泛用于进程或线程间的同步与互斥。
信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
PV原子操作是对整数计数器信号量sem的操作。
一次P操作使sem减一,而一次V操作使sem加一。
进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。
当信号量sem的值大于等于零时,该进程(或线程)具有公共资源的访问权限;
相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号量sem的值大于等于0为止。PV原子操作主要用于进程或线程间的同步和互斥这两种典型情况。
对于互斥,其基本流程图如下:
关于同步,其操作流程图如下图所示:
信号量的线程控制
Linux实现了POSIX的无名信号量,主要用于线程间的互斥与同步。以下主要介绍几个常见函数。
1、sem_init()
函数作用:用于创建一个信号量,并初始化它的值。
函数原型:int sem_init(sem_t *sem,int psharee,unsigned int value);
函数参数:sem:信号量指针;
pshared:0;
value:信号量的初始值;
返回值:成功0,出错-1;
头文件:#include <semaphore.h>
2、sem_wait()和sem_trywait()都相当于P操作,在信号量大于零时它们都能将信号量的值减一,两者的区别在于若信号量小于零时,sem_wait()将会阻塞进程,而sem_trywait()则会立即返回。
sem_wait()
函数原型:int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t *sem);v操作
int sem_getvalue(sem_t *sem);
int sem_destroy(sem_t *sem);
函数参数:sem:信号量指针;
返回值:成功0,出错-1;
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem1,sem2;
void *myThread1(void)
{
int i;
sem_wait(&sem1);
for(i = 0;i < 3;i++)
{
printf("hello hello.\n");
sleep(1);
}
sem_post(&sem2);
}
void *myThread2(void)
{
int i;
sem_wait(&sem2);
for(i = 0;i < 5;i++)
{
printf("world world.\n");
sleep(1);
}
sem_post(&sem1);
}
int main()
{
int i = 0;
int ret = 0;
pthread_t id1,id2;
sem_init(&sem1,0,0);
sem_init(&sem2,0,1);
ret = pthread_create(&id1,NULL,(void *)myThread1,NULL);
if(ret)
{
printf("creat pthread error!\n");
return 1;
}
ret = pthread_create(&id2,NULL,(void *)myThread2,NULL);
if(ret)
{
printf("creat pthread error!\n");
return 1;
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}