3、mutex中计数器为0时,加锁失败,但也会返回,此时加锁是失败状态,一定不要去访问临界资源
4、非阻塞接口一般都需要搭配循环来使用。
第三个接口:int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
1、带有超时时间的加锁接口
2、不能直接获取互斥锁的时候,会等待abs_timeout时间
3、如果在这个时间内加锁成功了,直接返回,不需要再继续等待剩余的时间,并且表示加锁成功
4、如果超出了该时间,也返回了,但是加锁失败了,需要循环加锁
上述三个加锁接口,第一个接口用的最多。
6.3.4互斥量的解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
对上述所有的加锁接口,都可使用该函数解锁
解锁的时候,会将互斥锁当中计数器的值从0变为1,表示其它线程可以获取互斥量
6.4互斥锁的本质
1、在互斥锁内部有一个计数器,其实就是互斥量,计数器的值只能为0或者为1
2、当线程获取互斥锁的时候,如果计数器当前值为0,表示当前线程不能获取到互斥锁,也就是没有获取到互斥锁,就不要去访问临界资源
3、当前线程获取互斥锁的时候,如果计数器当前值为1,表示当前线程可以获取到互斥锁,也就是意味着可以访问临界资源
6.5互斥锁中的计数器如何保证了原子性?
获取锁资源的时候(加锁):
1、寄存器当中值直接赋值为0
2、将寄存器当中的值和计数器当中的值进行交换
3、判断寄存器当中的值,得出加锁结果
两种情况:

例:4个线程,对同一个全局变量进行减减操作
#include
#include #include #include #include #define NUMBER 4int g_val = 100;pthread_mutex_t mutex;//定义互斥锁void *ThreadWork(void *arg){ int *p = (int*)arg; pthread_detach(pthread_self());//自己分离自己,不用主线程回收它的资源了 while(1) { pthread_mutex_lock(&mutex);//加锁 if(g_val > 0) { printf("i am pid : %d,i get g_val : %dn",(int)syscall(SYS_gettid),g_val); --g_val; usleep(2); } else{ pthread_mutex_unlock(&mutex);//在所有可能退出的地方,进行解锁 break; } pthread_mutex_unlock(&mutex);//解锁 } pthread_exit(NULL);}int main(){ pthread_t tid[NUMBER]; pthread_mutex_init(&mutex,NULL);//互斥锁初始化 int i = 0; for(;i < NUMBER;++i) { int ret = pthread_create(&tid[i],NULL,ThreadWork,(void*)&g_val);//不要传临时变量,这里是示范 if(ret != 0) { perror("pthread_create"); return -1; } } //pthread_join(tid,NULL);//线程等待 //pthread_detach(tid);//线程分离 pthread_mutex_destroy(&mutex);//销毁互斥锁 while(1) { printf("i am main work threadn"); sleep(1); } return 0;}
6.6互斥锁公平嘛?
互斥锁是不公平的。
内核维护等待队列, 互斥量实现了大体上的公平; 由于等待线程被唤醒后, 并不自动持有互斥量, 需要和刚进入临界区的线程竞争(抢锁), 所以互斥量并没有做到先来先服务。
6.7互斥锁的类型
1、PTHREAD_MUTEX_NORMAL: 最普通的一种互斥锁。 它不具备死锁检测功能, 如线程对自己锁定的互斥量再次加锁, 则会发生死锁。
2、
PTHREAD_MUTEX_RECURSIVE_NP: 支持递归的一种互斥锁, 该互斥量的内部维护有互斥锁的所有者和一个锁计数器。 当线程第一次取到互斥锁时, 会将锁计数器置1, 后续同一个线程再次执行加锁操作时, 会递增该锁计数器的值。 解锁则递减该锁计数器的值, 直到降至0, 才会真正释放该互斥量, 此时其他线程才能获取到该互斥量。 解锁时, 如果互斥量的所有者不是调用解锁的线程, 则会返回EPERM。
3、
PTHREAD_MUTEX_ERRORCHECK_NP: 支持死锁检测的互斥锁。 互斥量的内部会记录互斥锁的当前所有者的线程ID(调度域的线程ID) 。 如果互斥量的持有线程再次调用加锁操作, 则会返回EDEADLK。 解锁时, 如果发现调用解锁操作的线程并不是互斥锁的持有者, 则会返回EPERM。