同步:
当多个线程共享相同的内存时,需要每一个线程看到相同的试图,当一个线程修改变量时,其他线程也可以读取或修改这个变量,就需要线程的同步,确保他们不会访问到无效的变量。
互斥量:
在变量修改时间多于以一个存储器访问周期的处理器结构中,当存储器的读和写这两个周期交叉时,这种潜在的不一致性就会出现,当然这与处理器相关,但是在可移植的程序中不能对处理器做出任何预设。
互斥锁
为了让线程访问数据不产生中途,需要对变量加锁,使得同一时刻只有一个线程可以访问变量,互斥量的本质就是锁。
互斥量初始化;
1.动态分配,pthread_mutex_init()
2.静态分配,设置为常量PTHREAD_MUTEX_INTIALIZER
3.动态分配的互斥量在释放内存之前需要调用pthread_mutex_destroy()
int pthread_mutex_init(pthread_mutex_t restrict mutex, const pthread_mutexattr_t restrict attr);
参数:初始化的互斥量 ; 互斥量的属性,默认为NULL
int pthread_mutex_destroy(pthread_mutex_t mutex);
删除
int pthread_mutex_lock(pthread_mutex_t *mutex); //加锁
成功返回0 ,失败返回错误码。如果是已经被锁住的,导致该线程阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex); //试图加锁
成功返回0 ,失败返回错误码。如果是已经被锁住的,导致该线程阻塞
int pthread_mutex_unlock(pthread_mutex_t *mutex);
成功返回0 ,失败返回错误码
struct student
{
}stu;
int i;
pthread_mutex_t mutex;
void *thread_fun1(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);//加锁
/*
对结构体变量赋值
*/
pthread_mutex_unlock(&mutex);//解锁
}
}
void *thread_fun2(void *arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
/*
对结构体变量赋值
*/
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t tid1, tid2;
int err;
err =pthread_mutex_init(&mutex,NULL);//初始化
pthread_jion(tid1,NULL);
pthread_jion(tid2,NULL);
pthread_mutex_destroy(&mutex);
}
这样对结构体变量赋值时,只会同步在一个线程中执行,不加锁会产生错错乱。
读写锁与互斥量类似,不过互斥量要么加锁要么不加,而且同一时刻只允许一个线程加锁。
pthread_rwlock rwlock
读写锁有三种状态,读模式下加锁,写模式下加锁,不加锁,一次只有一个线程可以站偶写模式下的读写锁,但是多个线程可以同时站有读模式的读写锁。
读写锁非常适合对数据结构读次数大于写次数的程序,当它以读模式锁住时,是以共享的方式锁住的;当它以写模式锁住时,是以独占的模式锁住的。
初始化
int pthread_rwlock_init(pthread_rwlock_t restrict rwlock, const pthread_rwlockattr_t restrict attr);
使用完需要销毁
int pthread_rwlock_destroy(pthread_rwlock_t rwlock);
读模式加锁
写模式加锁
解锁
pthread_rwlock_t rwlock;
void *thread_fun1(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);//加锁
printf("thread1 print num %d",num );
sleep(5);
printf("thread1 over\n");
pthread_rwlock_unlock(&rwlock);//解锁
}
}
void *thread_fun2(void *arg)
{
while(1)
{
pthread_rwlock_wrlock(&rwlock);
printf("thread1 print num %d",num );
sleep(5);
printf("thread1 over\n");
pthread_rwlock_unlock(&rwlock);//解锁
}
}
int main()
{
pthread_t tid1, tid2;
int err;
err =pthread_rwlock_init(rwlock,NULL);//初始化
pthread_jion(tid1,NULL);
pthread_jion(tid2,NULL);
pthread_rwlock_destroy(&rwlock);
}
如果先运行的是写加锁,后续无论读写都要等写解锁,若识先运行读加锁,后续读写都能,且读锁会为后续写锁先行。
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
pthread_cond_t cond
例:
#include "stdio.h"
#include "pthread.h"
#include "stdlib.h"
#include "signal.h"
#include "string.h"
#include "unistd.h"
#define BUFFER_SIZE 5 //产品库存大小
#define PRODUCT_CNT 30 //产品生产总数
struct product_cons
{
int buffer[BUFFER_SIZE];
pthread_mutex_t lock; //互斥锁
int readpos,writepos; //读写位置
pthread_cond_t notempty; //条件变量,非空
pthread_cond_t notfull; //非满
}buffer;
void init(struct product_cons *p)
{
pthread_mutex_init(&p->lock,NULL);//互斥锁
pthread_cond_init(&p->notempty,NULL);//条件变量-非空
pthread_cond_init(&p->notfull,NULL);//条件变量非满
p->readpos =0;//起始位置都为0
p->writepos =0;
}
void finish(struct product_cons *p)
{
pthread_mutex_destroy(&p->lock);//互斥锁
pthread_cond_destroy(&p->notempty); //删除条件变量
pthread_cond_destroy(&p->notfull);
p->readpos =0; //结束都归0
p->writepos =0;
}
void put(struct product_cons *p,int data)//生产品到buffer
{
pthread_mutex_lock(&p->lock);//互斥锁,避免读写混乱
if((p->writepos+1)%BUFFER_SIZE==p->readpos)//如9+1%5=0 说明刚取走第四个,放入第九个需要等待
{
printf("producer wait for full\n");
pthread_cond_wait(&p->notfull, &p->lock);//等待非满
}
p->buffer[p->writepos] =data;
p->writepos ++; //存储位置+1
if(p->writepos >=BUFFER_SIZE) //满了 归零。
p->writepos =0;
pthread_cond_signal(&p->notempty);//发出非空
pthread_mutex_unlock(&p->lock);
}
int get(struct product_cons *p)
{
int data;
pthread_mutex_lock(&p->lock);
if(p->readpos==p->writepos)//读追上了写,说明读完
{
printf("consumer wait for not empty\n");
pthread_cond_wait(&p->notempty,&p->lock);//阻塞当前线程,等待put发送非空信号才能获取
}
data=p->buffer[p->readpos];
p->readpos++;
if(p->readpos>=BUFFER_SIZE)
p->readpos=0;
pthread_cond_signal(&p->notfull); //发出非满
pthread_mutex_unlock(&p->lock);
return data;
}
void *producer(void *data)//每隔1秒生产一个
{
int n;
for(n=1;n<=50;++n)//生产50个
{
sleep(2);
printf("put the %d product...\n",n);
put(&buffer,n);//把n写到buffer里
printf("put the %d product success\n",n);
}
printf("producer stopped\n");
return NULL;
}
void *consumer(void *data) //每隔2秒消费一个
{
static int cnt =0;
int num;
while(1)
{
sleep(1);
printf("get product...\n");
num =get(&buffer);
printf("get the %d product success\n",num);
if(++cnt == PRODUCT_CNT) break; //计满30
}
printf("consumer stopped\n");
return NULL;
}
int main(int argc, char argv[])
{
pthread_t th_a,th_b;
void *retval;
init(&buffer);
pthread_create(&th_a,NULL,producer,0);
pthread_create(&th_b,NULL,consumer,0);
pthread_join(th_a,&retval);
pthread_join(th_b,&retval);
finish(&buffer); //销毁互斥量
return 0;
}