网站建设推广工资,获客,沈阳集团网站建设,家居企业网站建设如何目录
一、互斥锁基本概念
1.1 互斥相关背景概念
1.2 互斥锁(mutex)
1.3 死锁
二、初始化互斥锁
2.1 静态初始化 2.2 动态初始化
三、获取与释放互斥锁
四、销毁互斥锁 一、互斥锁基本概念
1.1 互斥相关背景概念 临界资源#xff1a;多线程执行流共享的资源就叫做…目录
一、互斥锁基本概念
1.1 互斥相关背景概念
1.2 互斥锁(mutex)
1.3 死锁
二、初始化互斥锁
2.1 静态初始化 2.2 动态初始化
三、获取与释放互斥锁
四、销毁互斥锁 一、互斥锁基本概念
1.1 互斥相关背景概念 临界资源多线程执行流共享的资源就叫做临界资源临界区每个线程内部访问临界资源的代码就叫做临界区互斥任何时刻互斥保证有且只有一个执行流进入临界区访问临界资源通常对临界资源起保护作用。原子性不会被任何调度机制打断的操作该操作只有两态要么完成要么未完成。 1.2 互斥锁(mutex) 当不同进程/线程去访问某个临界资源的时候就需要进行互斥保护 这种互斥保护可以看做是一种锁机制就好比当你去上厕所的时候你会锁住门不让别人进来。 在Linux系统中的锁机制是一个比较广泛的概念而且锁的种类很多包括互斥锁文件锁读写锁等等。 在初始化的时候互斥锁处于开锁的状态当互斥锁被线程持有时该互斥锁处于闭锁状态线程获得互斥锁的所有权。当该线程释放互斥锁时 该互斥锁处于开锁状态线程失去该互斥锁的所有权。也就是说同时只有一个线程能获取互斥锁特别地持有该互斥锁的线程能够再次获得这个锁而不被阻塞 这就是互斥锁的递归访问。互斥锁多用于保护临界资源。 1.3 死锁 死锁就是自己把自己阻塞了就相当于自己把自己锁在门外钥匙在屋里。还有一种死锁的的情况是 两个线程相互阻塞就好比你家的钥匙在你朋友家你朋友家的钥匙在你家然后你们都进不去。想要避免死锁最好遵循以下的规则 对共享资源操作前一定要获得锁。 完成操作以后一定要释放锁。 尽量短时间地占用锁。 如果有多个锁如获得顺序是ABC连环扣释放顺序也应该是ABC。 二、初始化互斥锁
2.1 静态初始化 在使用互斥锁前需要初始化一个互斥锁而在POSIX标准中支持互斥锁静态初始化和动态初始化两种方式 如果是静态初始化的可以通过以下代码实现选择其中一句即可 pthread_mutex_t fastmutex PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; pthread_mutex_t是互斥锁的结构体其实就是定义一个互斥锁结构并且将其赋值代表不同的互斥锁 这3种锁的区别主要在于其他未占有互斥锁的线程在获取互斥锁时是否需要阻塞等待 PTHREAD_MUTEX_INITIALIZER表示默认的互斥锁即快速互斥锁。互斥锁被线程1持有时此时互斥锁处于闭锁状态 当线程2尝试获取互斥锁那么线程2将会阻塞直至持有互斥锁的线程1解锁为止。 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP递归互斥锁。互斥锁被线程1持有时线程2尝试获取互斥锁 将无法获取成功并且阻塞等待而如果是线程1尝试再次获取互斥锁时将获取成功并且持有互斥锁的次数加1。 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP检错互斥锁。这是快速互斥锁的非阻塞版本它会立即返回一个错误代码线程不会阻塞。 2.2 动态初始化 互斥锁动态初始化可以调用pthread_mutex_init()函数该函数原型如下 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); pthread_mutex_init()函数是以动态方式初始化互斥锁的参数说明如下 mutex则是初始化互斥锁结构的指针。 mutexattr是属性参数它允许我们设置互斥锁的属性从而属性控制着互斥锁的行为如果参数mutexattr为NULL 则使用默认的互斥锁属性默认属性为快速互斥锁。 三、获取与释放互斥锁 线程对互斥锁的所有权是独占的任意时刻互斥锁只能被一个线程持有如果互斥锁处于开锁状态 那么获取该互斥锁的线程将成功获得该互斥锁并拥有互斥锁的所有权 而如果互斥锁处于闭锁状态则根据互斥锁的类型做对应的处理默认情况下是快速互斥锁 获取该互斥锁的线程将无法获得互斥锁线程将被阻塞直到互斥锁被释放当然如果是同一个线程重复获取互斥锁也会导致死锁结果。获取互斥锁有2个函数mutex参数指定了要操作的互斥锁 int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex); pthread_mutex_lock()函数获得访问临界资源的权限如果已经有其他线程锁住互斥锁那么该函数会是线程阻塞指定该互斥锁解锁为止。 pthread_mutex_trylock()是pthread_mutex_lock()函数的非阻塞版本使用它不会阻塞当前线程如果互斥锁已被占用它会理解返回一个EBUSY错误。 访问完共享资源后一定要通过pthread_mutex_unlock()函数释放占用的互斥锁以便系统其他线程有机会获取互斥锁访问该资源。 简单说就是互斥锁的使用流程应该是 线程获取互斥锁。 然后访问共享资源。 最后释放互斥锁。 四、销毁互斥锁 pthread_mutex_destroy()函数用于销毁一个互斥锁当互斥锁不再使用时可以用它来销毁mutex参数指定了要销毁的互斥锁 int pthread_mutex_destroy(pthread_mutex_t *mutex);
#include unistd.h
#include fcntl.h
#include stdio.h
#include stdlib.h
#include pthread.h#define THREAD_NUMBER 3 /* 线程数 */pthread_mutex_t mutex;void *thread_func(void *arg)
{int num (int)arg;int res;/* 互斥锁上锁 */res pthread_mutex_lock(mutex);if (res){ /*获取失败*/printf(Thread %d lock failed\n, num);/* 互斥锁解锁 */pthread_mutex_unlock(mutex);pthread_exit(NULL);}printf(Thread %d is hold mutex\n, num);/*睡眠一定时间*/sleep(2);printf(Thread %d freed mutex\n\n, num);/* 互斥锁解锁 */pthread_mutex_unlock(mutex);pthread_exit(NULL);
}int main(void)
{pthread_t thread[THREAD_NUMBER];int num 0, res;/* 互斥锁初始化 */pthread_mutex_init(mutex, NULL);for (num 0; num THREAD_NUMBER; num){/*创建线程*/res pthread_create(thread[num], NULL, thread_func, (void*)num);if (res ! 0){printf(Create thread %d failed\n, num);exit(res);}}for (num 0; num THREAD_NUMBER; num){/*等待线程结束*/pthread_join(thread[num], NULL);}/*销毁互斥锁*/pthread_mutex_destroy(mutex);return 0;
} 系统创建3个线程假设这3个线程中有临界资源被访问那么我们希望这3个线程按顺序且不能同时去访问这个临界资源假设临界资源是调用sleep()函数所以我们可以使用互斥锁去限制能访问的线程获取到互斥锁的线程可以访问临界资源。从实验结果可以看到线程访问临界资源的顺序每次执行顺序都是不一样的并且临界区相同时间只允许一个线程访问。