1. 背景知识:
多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的某些同步操作
• 互斥锁:为了使不同线程互斥的使用某个资源
○ 锁的创建:pthread_mutex_init
§ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
§ int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr);
○ 锁的属性:
pthread_mutexattr_init(pthread_mutexattr_t *mattr)
pthread_mutexattr_settype(pthread_mutexattr_t *attr , int type)
pthread_mutexattr_gettype(pthread_mutexattr_t *attr , int *type)
§ 普通锁:PTHREAD_MUTEX_TIMED_NP(当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性)
§ 嵌套锁:PTHREAD_MUTEX_RECURSIVE_NP(允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争)
§ 检错锁:PTHREAD_MUTEX_ERRORCHECK_NP(如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁)
§ 适应锁:PTHREAD_MUTEX_ADAPTIVE_NP(动作最简单的锁类型,仅等待解锁后重新竞争)
○ 锁的释放:pthread_mutex_destory
○ 锁操作:
§ 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex)
§ 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex)
§ 测试加锁:int pthread_mutex_trylock(pthread_mutex_t *mutex)
• 条件锁:为了保证不同线程之间有顺序(通过条件控制)地完成某个流程
○ 等待方式:
§ 无条件等待:pthread_cond_wait()
§ 计时等待:pthread_cond_timedwait()
○ 激活条件:
§ int pthread_cond_signal(pthread_cond_t *cond); 激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个
§ int pthread_cond_broadcast(pthread_cond_t *cond); 激活所有等待线程
互斥锁:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex ;
void *print_msg(void *arg){
int i=0;
pthread_mutex_lock(&mutex);
for(i=0;i<15;i++){
printf("output : %d\n",i);
usleep(100);
}
pthread_mutex_unlock(&mutex);
}
int main(int argc,char** argv){
pthread_t id1;
pthread_t id2;
pthread_mutex_init(&mutex,NULL);
pthread_create(&id1,NULL,print_msg,NULL);
pthread_create(&id2,NULL,print_msg,NULL);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_mutex_destroy(&mutex);
return 1;
}
条件锁:
//一个生产者消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
typedef struct node
{
int num;
struct node *next;
} node_t;
typedef node_t *list_t;
list_t head = NULL;
pthread_mutex_t mutex =
PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond =
PTHREAD_COND_INITIALIZER;
//消费者线程
void *consume(void *arg)
{
node_t *tmp;
while (1)
{
//加锁
pthread_mutex_lock(&mutex); //对临界变量加锁
if (head == NULL) //如果头部指向空,等待
pthread_cond_wait(&cond, &mutex);
tmp = head; //将要删除的节点赋值给中间值,然后头指针指向下一个
head = head->next; //
//解锁
pthread_mutex_unlock(&mutex);
//消费tmp节点
printf("consum:%d\n", tmp->num);
free(tmp);
tmp = NULL;
sleep(rand() % 5);
}
}
//生产者线程
void *product(void *arg)
{ //函数的格式void *(*start_routine) (void *),返回值是指针,参数也是
node_t *n;
while (1)
{
//生产一个新的节点
n = (node_t *)malloc(sizeof(node_t));
n->num = rand() % 1000 + 1;
printf("p:%d\n", n->num);
//加锁
pthread_mutex_lock(&mutex);
//将新节点放入到链表的头部
n->next = head;
head = n;
//解锁
pthread_mutex_unlock(&mutex);
//通知消费者
pthread_cond_signal(&cond);
sleep(rand() % 5);
}
}
int main(void)
{
pthread_t pid, cid;
//设置随机数的种子
srand(time(NULL));
//创建两个线程,用于生产者和消费者
pthread_create(&pid, NULL, product, NULL); //创建线程后即执行该线程
pthread_create(&cid, NULL, consume, NULL); //参数含义是(存放ID的缓存区,NULL缺省属性,线程的执行函数,函数的唯一参数)
//等待线程的汇合
pthread_join(pid, NULL);
pthread_join(cid, NULL);
//销毁mutex锁
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}