1.条件变量
条件变量本身不是锁!但它也可以造成线程阻塞
通常与互斥锁配合使用。给多线程提供一个会合的场所。
1.主要函数应用
pthread_cond_init函数
pthread_cond_destroy函数
pthread_cond_wait函数
pthread_cond_timedwait函数
pthread_cond_signal函数
pthread_cond_broadcast函数
以上6 个函数的返回值都是,成功返回0,失败直接返回错误号
pthread_cond_t类型用于定义条件变量
pthread_cond_t cond;
pthread_cond_init函数 初始化一个条件变量
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr *restrict attr);参1:需要初始化的条件变量参2:arrt表条件比那里属性,通常为默认值,传NULL即可
1.动态初始化:pthread_cond_init(&cond,NULL)2.静态初始化: pthread_cond_t cond = PTHREAD_COND_INITIALIZER ;
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);参1:已经初始化号的条件变量,如果条件不满足,则一直阻塞等待参2:一把已加锁的互斥锁,解锁已加锁的mutex,等价pthread_mutex_unlock(&mutex)参1、参2执行时是原子操作。(也就阻塞时,会继续操作解锁,中途不会被中断)函数返回return前:当条件必须满足,同步解除阻塞并重新给互斥量加pthread_mutex_lock(&mutex)
int pthread_cond_signal(&cong);参1:已经初始化好的条件变量

例程:生产-消费者模型代码
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
/*链表作为公享数据,需被互斥量保护*/
#define SIZE 100
int repository[SIZE]={0};//定义仓库大小,并初始化为0
/*静态初始化一个条件变量和一个互斥量*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int empty_repository(int arr[])
{
int i,sum=0;
for(i=0;i<SIZE;i++)
{
sum += arr[i];
}
return sum;
}
int fill_repository(int arr[])
{
int i,sum;
for(i=0;i<SIZE;i++)
{
if(arr[i]==0)
{
arr[i]= rand() % 1000 + 1;
printf("-------fill a[%d]=%d\n",i,arr[i]);
return arr[i];
}
}
return -1;
}
int del_repository(int arr[])
{
int i,temp;
for(i=SIZE;i>=0;i--)
{
if(arr[i]!=0)
{
temp=arr[i];
printf("-------del a[%d]=%d\n",i,arr[i]);
arr[i]= 0;
return temp;
}
}
return -1;
}
void *consumer(void *p)
{
for (;;)
{
int ret=pthread_mutex_lock(&lock);
if(ret !=0)
{
printf("consumer mutex_lock err:%s\n",strerror(ret));
}
while (!empty_repository(repository))
{
//如果条件不满足,释放锁,并阻塞在此处
//如果条件满足,重新加锁,并解除阻塞,进行循环条件判断
printf("cond_wait test mask\n");
pthread_cond_wait(&has_product, &lock);
}
//模拟消费掉一个产品
ret=del_repository(repository);
if(ret==-1)
{
printf("del_repository() err\n");
pthread_exit(NULL);
}
pthread_mutex_unlock(&lock);
printf("-Consume %lu---Produce id=%d\n", pthread_self(), ret);
sleep(rand() % 5);
}
}
void *producer(void *p)
{
for (; ;)
{ //sleep(5),为验证consumer线程中的,pthread_cond_wait()会进行解锁+阻塞功能
sleep(5);
//生产者拿锁成功,再生产产品
int ret=pthread_mutex_lock(&lock);
if(ret !=0)
{
printf("producer mutex_lock() err:%s\n",strerror(ret));
pthread_mutex_unlock(&lock);
break;//跳出循环
}
//模拟生产一个产品
ret=fill_repository(repository);
if(ret==-1)
{
printf("fill_repository() err\n");
pthread_mutex_unlock(&lock);
break;
// pthread_exit(NULL);//生产仓库满后,无法继续生产,退出生产线程
}
pthread_mutex_unlock(&lock);
printf("-producer %lu---Produce id=%d\n", pthread_self(), ret);
pthread_cond_signal(&has_product); //条件满足了,通知等待条件变量has_product的
线程
usleep(100000);
}
}
int main(int argc, char *argv[])
{
pthread_t tid01, tid02,tid03;
srand(time(NULL));
pthread_create(&tid01, NULL, producer, NULL);
pthread_create(&tid02, NULL, consumer, NULL);
// pthread_create(&tid03, NULL, consumer, NULL);
pthread_join(tid01, NULL);
pthread_join(tid02, NULL);
// pthread_join(tid03, NULL);
return 0;
}
2.信号量
信号量是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。
由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据锁住。这样的话虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接 使用单进程无异。
主要函数
sem_init函数
sem_destroy函数
sem_wait函数
sem_trywait函数
sem_timedwait函数
sem_post函数
以上6个函数的返回值都是:成功返回0,失败返回-1,同时设置errno(注意,他们没有pthread)前缀
sem_t类型,本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节(类似于使用文件描述符)。
sem_tsem规定信号量sem不能<0 头文件<semaphore.h>
信号的基本操作
sem_wait:1.信号量大于0,则信号量-- (类比pthread_mutex_lock)。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#define NUM 5
int queue[NUM]; //全局数组实现环形队列
sem_t blank_number,product_number; //空格子信号量,产品信号量
void *producer(void *arg)
{
int i = 0;
while(1)
{
sem_wait(&blank_number); //生产者将空格子数--,为0则阻塞等待
queue[i] = rand() % 1000 + 1;//生产一个产品
printf("----produce-----%d\n",queue[i]);
sem_post(&product_number); //将产品数++
i = (i+1)%NUM;//借助下标实现环形
sleep(rand()%1);
}
}
void *consumer(void *arg)
{
int i=0;
while(1)
{
sem_wait(&product_number);//消费者将产品数--,为则阻塞等待
printf("---consume-----%d\n",queue[i]);
queue[i] = 0;//消费一个产品
sem_post(&blank_number);//消费掉以后,将空格子数++
i = (i+1) % NUM;
sleep(rand()%3);
}
}
int main(int argc,char *argv[])
{
pthread_t pid,cid;
sem_init(&blank_number,0,NUM);//初始化线程间共享-0,空格子信号量为5
sem_init(&product_number,0,0);//初始化线程间共享-0,产品数为0
pthread_create(&pid,NULL,producer,NULL);
pthread_create(&cid,NULL,consumer,NULL);
pthread_join(pid,NULL);
pthread_join(cid,NULL);
sem_destroy(&blank_number);
sem_destroy(&product_number);
return 0;
}