在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
互斥锁(Mutex)是在原子操作API的基础上实现的信号量行为。互斥锁不能进行递归锁定或解锁,能用于交互上下文但是不能用于中断上下文,同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。
互斥锁是一种简单的加锁的方法来控制对共享资源的存取,当多个线程访问公共资源时,为了保证同一时刻只有一个线程独占资源,就可以通过互斥锁加以限制,在一个时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程才能够对共享资源进行操作。若其他线程希望上锁一个已经上锁了的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。
在Posix Thread中定义有一套专门用于线程同步的mutex函数。可以通过静态和动态两种方式创建互斥锁。
互斥锁有三个类型可供选择:
PTHREAD_MUTEX_TIMED_NP普通锁(默认锁):
当一个线程加锁以后,其余请求锁的线程将形成一个阻塞等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
PTHREAD_MUTEX_RECURSIVE_NP嵌套锁:
允许同一个线程对同一个锁成功获得多次,并通过多次unlock 解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
嵌套锁对同一线程可以重复上锁成功,对不同线程不能重复上锁。
嵌套锁在同一线程中重复上锁,需要重复解锁,否则其它线程将阻塞。
PTHREAD_MUTEX_ERRORCHECK_NP检错锁:
如果同一个线程请求同一个锁,则返回 EDEADLK,否则与普通锁类型动作相同。 这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
检错锁的主要特点就是: 同一个线程无法多次重复进行加锁, 第一次获取锁成功后, 没有解锁的情况下, 如果继续获取锁将不会阻塞, 会返回一个错误值(35)。
动态方式初始化互斥锁:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);
attr填NULL表示使用默认属性,创建普通锁。
//静态方式初始化互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//互斥锁上锁,多次请求则会阻塞
int pthread_mutex_lock(pthread_mutex_t *mutex);
//互斥锁上锁,多次请求不会阻塞,会返回上锁失败错误信息
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//互斥解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。
#include
#include
#include
/*
1.创建1个线程,子线程先打印10遍hello,world,然后主线程再打印5遍”12346”,按次顺序循环50次。
*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁1
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁2
void *pth_work(void *arg)
{
int i,j;
for(i=0;i<50;i++)
{
pthread_mutex_lock(&mutex);
printf("-----------子线程第%d遍-----------\n",i);
for(j=0;j<10;j++)
{
printf("hello,world\n");
}
pthread_mutex_unlock(&mutex2);
}
}
int main()
{
int i=0,j;
pthread_t pthid;
pthread_mutex_lock(&mutex2);
/*创建子线程*/
pthread_create(&pthid,NULL,pth_work,NULL);//创建线程
pthread_detach(pthid);
for(i=0;i<50;i++)
{
pthread_mutex_lock(&mutex2);//互斥锁上锁
printf("-----------主线程第%d遍-----------\n",i);
for(j=0;j<5;j++)//主线程打印
{
printf("123456\n");
}
pthread_mutex_unlock(&mutex);
}
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
}
2.创建3线程,线程1打印A,线程2打印B,线程3打印C,按照ABC顺序输出10遍。
#include
#include
#include
/*
2.创建3线程,线程1打印A,线程2打印B,线程3打印C,按照ABC顺序输出10遍。
*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁1
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁2
pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥锁3
void *pth_work(void *arg)
{
int cnt=(int *)arg;
//printf("cnt=%d\n",cnt);
for(int i=0;i<10;i++)
{
if(cnt==0)//线程1
{
pthread_mutex_lock(&mutex);
printf("A");
pthread_mutex_unlock(&mutex2);
}
if(cnt==1)//线程2
{
pthread_mutex_lock(&mutex2);
printf("B");
pthread_mutex_unlock(&mutex3);
}
if(cnt==2)//线程3
{
pthread_mutex_lock(&mutex3);
printf("C");
fflush(stdout);//刷新缓冲区
pthread_mutex_unlock(&mutex);
}
}
}
int main()
{
int i=0;
pthread_t pthid[3];
pthread_mutex_lock(&mutex2);
pthread_mutex_lock(&mutex3);
/*创建3个子线程*/
for(i=0;i<3;i++)
{
pthread_create(&pthid[i],NULL,pth_work,(void *)i);
}
/*等待线程结束*/
for(i=0;i<3;i++)
{
pthread_join(pthid[i],NULL);
}
printf("\n所有子线程结束,程序退出!\n");
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
pthread_mutex_destroy(&mutex3);
}
运行效果:
[wbyq@wbyq ubuntu]$ ./app
ABCABCABCABCABCABCABCABCABCABC
所有子线程结束,程序退出!