##互斥互斥量如前所述,如果系统中存在资源共享,线程之间存在竞争,没有合理的同步机制,就会出现数据混乱。为了实现同步机制,Linux中提供了多种方式,其中一种方式就是互斥锁mutex(也叫mutex)。互斥锁的具体实现方式如下:每个线程在对共享资源进行操作之前,都尝试对其进行加锁,加锁成功后才能对共享资源进行读写操作,操作完成后解锁。互斥并不是为了消除竞争。其实资源还是共享的,线程还是在竞争的,只是通过这种“锁”机制,对共享资源的访问变成了互斥操作,也就是说,一个线程操作这个资源时,其他线程就不能对其进行操作,从而消除与时间相关的错误。从互斥量的实现机制可以看出,同一时刻只能有一个线程持有锁。如果有多个线程同时持有锁,那就没意义了。但是,这种锁定机制不是强制性的。互斥量本质上是操作系统提供的“建议锁”(也称为“合作锁”)。当一个程序中有多个线程访问共享资源时,推荐使用这种机制。因此,即使有互斥量,如果其他线程不遵循这种锁机制访问共享数据,仍然会发生数据混乱。所以为了避免这种情况,所有访问共享资源的线程都必须使用相同的锁机制。主要应用函数:pthread_mutex_init函数pthread_mutex_destroy函数pthread_mutex_lock函数pthread_mutex_trylock函数pthread_mutex_unlock函数以上五个函数的返回值分别是:成功返回0,失败返回错误号。在Linux环境中,pthread_mutex_t类型本质上是一个结构体。但是,为了简化理解,在应用时可以忽略具体的实现细节,简单的作为整数处理。Mutex一般是这样定义的:pthread_mutex_tmutex;变量mutex只有1和0两个值。##pthread_mutex_init函数函数原型:intpthread_mutex_init(pthread_mutex_trestrictmutex,constpthread_mutexattr_trestrictattr);函数功能:初始化一个互斥体(mutex)互斥量,初始值可视为1;参数介绍:mutex:传出参数,调用时要通过&mutex给这个函数;这里有一个特殊的关键字:restrict。它的作用只是用来限制指针,告诉编译器,所有修改内存中指向的指针内容的操作,都只能通过这个指针来完成。它不能被除此指针以外的其他变量或指针修改。比如定义一个pthread_mutex_t指针,赋给mutex的值,用来修改mutex指向的内存,这是不允许的。attr:互斥属性。它是一个传入参数,通常传递NULL,表示使用默认属性(即:线程间共享)。互斥锁的初始化有两种方式:静态初始化:如果互斥锁是静态分配的,即定义为全局变量,或者用static关键字修饰,可以直接用宏初始化。例如pthead_mutex_tmuetx=PTHREAD_MUTEX_INITIALIZER;动态初始化:如果mutex互斥量定义为局部变量,则应使用动态初始化。例如pthread_mutex_init(&mutex,NULL)##pthread_mutex_destroy函数函数原型:intpthread_mutex_destroy(pthread_mutex_t*mutex);函数功能:销毁一个互斥量pthread_mutex_lock函数函数原型:intpthread_mutex_lock(pthread_mutex_t*mutex);函数功能:锁定共享资源。可以理解为mutex--(or-1);如果锁定不成功,该线程将阻塞,直到持有互斥量的其他线程被解锁。注意:访问共享资源前先锁定,访问后立即解锁。锁的“粒度”应该越小越好。pthread_mutex_unlock函数原型:intpthread_mutex_trylock(pthread_mutex_t*mutex);功能:解锁共享资源。可以这样理解,当mutex++(或+1);解锁后,所有阻塞在锁上的线程都会被唤醒。至于先唤醒哪个线程,取决于优先级和调度。默认情况下:最先阻塞的线程会最先被唤醒。##pthread_mutex_trylock函数函数原型:intpthread_mutex_trylock(pthread_mutex_t*mutex);功能:尝试锁定共享资源。它与pthread_mutex_lock函数的区别在于,在使用lock函数对共享资源进行加锁时,如果加锁不成功,线程将被阻塞;而如果使用trylock,则当前线程在加锁不成功时不会被阻塞,而是立即返回一个描述互斥量情况的值。死锁:一个线程试图锁定同一个互斥体A两次。线程1拥有A锁,请求B锁;线程2拥有B锁并请求A锁time(NULL));while(1){pthread_mutex_lock(&mutex);printf("hello");//标准输出是共享资源sleep(rand()%3);//此时会丢失CPUprintf("world!\n");pthread_mutex_unlock(&mutex);sleep(rand()%3);}returnNULL;}intmain(){pthread_ttid;intn=5;srand(time(NULL));pthread_mutex_init(&mutex,NULL);pthread_create(&tid,NULL,tfn,NULL);while(n--){pthread_mutex_lock(&mutex);printf("HELLO");sleep(rand()%3);printf("WORLD!\n");pthread_mutex_unlock(&mutex);sleep(rand()%3);}pthread_cancel(tid);pthread_join(tid,NULL);pthread_mutex_destroy(&mutex);return0;}本文转载有来自公众号“良序Linux”的授权。世界500强外企Linux开发工程师梁旭,在公众号分享大量Linux干货,欢迎关注!
