由于线程是共享进程的资源和空间的,所以对这些资源进行操作时,必须考虑到线程间资源访问的同步与互斥问题,这里主要说的是POSIX中的两种线程同步机制,分别为互斥锁和信号量,这两种同步机制能够互相调用对方来实现,但互斥锁使用与同时可用的资源是唯一的情况,信号量更适用于同时可用的资源为多个的情况。
互斥锁:是一种简单的加锁方法来控制对共享资源的原子操作,这个互斥锁只有两种状态:上锁,解锁,可以把互斥锁看成某种意义上的全局变量,在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作,若其他线程希望上锁一个已经被上锁的互斥锁,则被挂起,直到上锁的线程释放掉互斥锁为止,所以互斥锁保证了每个线程对共享资源按顺序进行原子操作。
互斥锁主要包括下面的基本函数:
互斥锁初始化:pthread_mutex_init()
互斥锁上锁:pthread_mutex_lock()
互斥锁判断上锁:pthread_mutex_trylock()
互斥锁解锁:pthread_mutex_unlock()
消除互斥锁:pthread_mutex_destroy()
互斥锁分为快速互斥锁,递归互斥锁,检错互斥锁。这三种锁得区别主要是在未占有互斥锁的线程在希望得到互斥锁时是否需要阻塞等待,默认的是快速互斥锁
快速锁:调用线程会阻塞直到拥有互斥锁得线程解锁为止
递归互斥锁:能够成功的返回,并且增加调用线程在互斥锁上加锁的次数
检错互斥锁:快速互斥锁的非阻塞版本,他会立即返回一个错误信息
pthread_mutex_init()函数格式如下:
pthread_mutex_lock()等函数的语法如下:
下面的这个实例是在前面的基础上增加了锁功能,实现原本独立与无序的线程按顺序执行:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_NUMBER 3//线程个数
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0
void *thrd_func(void *arg)//线程函数
{
int thrd_num = (int)arg ;
int delay_time = 0 ;
int count = 0 ;
int res ;
res = pthread_mutex_lock(&mutex) ;//上锁
if (res)
{
printf("thread %d lock failed\n", thrd_num) ;
pthread_exit(NULL) ;
}
printf("thread %d is starting\n", thrd_num) ;
for (count = 0; count < REPEAT_NUMBER; count++)//每个线程完成五次任务
{
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;//产生随机时间
sleep(delay_time) ;
printf("\tThread %d:job %d delay = %d\n",
thrd_num, count, delay_time) ;
}
printf("thread %d finished\n", thrd_num) ;
pthread_exit(NULL) ;
}
int main()
{
pthread_t thread[THREAD_NUMBER] ;
int no = 0, res ;
void *thrd_ret ;
srand(time(NULL)) ;//产生随机种子
pthread_mutex_init(&mutex, NULL ) ;//初始化互斥锁,默认的是快速互斥锁
for(no = 0; no < THREAD_NUMBER; no++)
{
res = pthread_create(&thread[no], NULL, thrd_func, (void *)no) ;//创建线程
if (res != 0)
{
printf("create thread %d failed\n", no) ;
exit(res) ;
}
}
printf("create threads success\n waiting for threads to finish...\n") ;
for (no = 0; no < THREAD_NUMBER; no++)
{
res = pthread_join(thread[no], &thrd_ret) ;//等待线程结束
if (!res)
{
printf("thread %d joined\n", no) ;
}
else
{
printf("thread %d joined failed", no) ;
}
pthread_mutex_unlock(&mutex) ;//解锁
}
pthread_mutex_destroy(&mutex) ;//消除锁
exit(0) ;
}
程序执行如下:
可以看出这个按照线程创建时的顺序执行的,第一个进程执行时上锁必须等到线程退出时才能解锁,下一个线程才能执行。