多线程应用在协同完成一个任务时既有分工有用协作,协作涉及数据交换、共享资源的访问及线程执行顺序的控制,分工可以并发执行,协作则需要同步的控制。在多线程中最基本的同步有互斥执行、条件同步、栅栏同步。
互斥变量用于多线程竞争访问某一共享资源,读写锁支持线程对共享数据的共享读互斥写,互斥变量给线程提供了互斥访问共享数据的手段它可以保证对共享数据访问的一致性。
1.互斥变量
1.1 互斥变量的初始化和销毁
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITALIZER; //初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr ); //初始化
int pthread_mutex_destory(pthread_mutex_t *mutex); //销毁
静态变量可以使用宏PTHREAD_MUTEX_INITALIZER初始化
互斥变量的两种属性值:
PTHREAD_PROCESS_PRIVATE 仅有同一个线程内部使用,该属性为默认值
PTHREAD_PROCESS_SHARED 可以由多个进程使用
互斥变量类型属性值
PTHREAD_MUTEX_NORMAL 基本类型,无内建差错检验、死锁检验。
PTHREAD_MUTEX_RECURSIVE 递归类型,允许一个进程多次加锁和解锁。
PTHREAD_MUTEX_ERRORCHECK 检查并报告简单的使用错误。
PTHREAD_MUTEX_DEFAULT 默认类型,可以映射为上面任何类型
1.2 互斥变量属性的初始化和销毁
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr); //初始化
int pthread_mutexattr_destroy(pthread_mutexattr_t *attrt); //销毁
1.3 互斥变量属性的设置和查询
#include <pthread.h>
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshread); //设置互斥变量为进程共享
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,int *restrict pshread); //获得进程共享互斥变量的属性
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int type); //设置互斥变量只用在一个进程中
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type); //获得互斥变量的属性
1.4 互斥变量的加锁和解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex); //加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex); //尝试加锁,不阻塞
int pthread_mutex_unlock(pthread_mutex_t *mutex); //解锁
1.5 互斥变量具体实例:
/*
* mutex.c
*
* Created on: 2016年11月6日
* Author: chy
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/errno.h>
#define Max 16
#define ERR(msg,f) { \
if(f < 0) { \
fprintf(stderr,"%s",msg); \
exit(1); \
} \
}
int a[Max],b[Max];
int MAX = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //互斥变量
void *find_max(int *f) //查找最大数据
{
int i,l_max = f[0];
for(i = 0; i < Max; i++)
if(l_max < f[i])
l_max = f[i];
int rv;
rv = pthread_mutex_lock(&mutex); //给互斥变量加锁
ERR("mutex lock failed\n",rv);
MAX = l_max > MAX ? l_max : MAX;
rv = pthread_mutex_unlock(&mutex); //解锁
ERR("mutex unlock failed\n",rv);
pthread_exit((void *)0);
}
int main(int argc,char *argv[])
{
pthread_t pthread_a,pthread_b;
srand(time(NULL)); //随机生成测试数据
for(int i = 0; i < Max; i++){
a[i] = rand() % 1024;
printf("%d ",a[i]);
}
printf("\n");
for(int i = 0; i < Max; i++){
b[i] = rand() % 1024;
printf("%d ",b[i]);
}
printf("\n");
ERR("create pthread_a failed\n",pthread_create(&pthread_a, NULL, (void*(*)())find_max, (void*)a)); //创建A线程
ERR("create pthread_b failed\n",pthread_create(&pthread_b, NULL, (void*(*)())find_max, (void*)b)); //创建B线程
pthread_join(pthread_a, NULL); //等待线程结束
pthread_join(pthread_b, NULL);
printf("a and b max num is:%d\n",MAX);
pthread_mutex_destroy(&mutex); //销毁互斥变量
exit(0);
}
2. 读写锁
2.1 读写锁的初始化和销毁
#include <pthread.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; //静态初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlock_t *restrict attr); //初始化
int pthread_rwlock_destroy(pthread_rwlock_t *restrict rwlock); //销毁
2.2 读写锁属性的初始化、销毁、设置和获取
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); //初始化读写锁属性
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); //销毁读写锁属性
int pthread_rwlockattr_getshared(const pthread_rwlockattr_t *restrict attr,int *restrict pshared); //获得属性类型
int pthread_rwlockattr_setshared(pthread_rwlockattr_t *attr,int pshared); //设置属性对象
2.3 读写上锁与解锁
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); //设置读锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); //尝试加读锁,阻塞进程
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); //设置写锁
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); //尝试加写锁,阻塞进程
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); //解锁
2.4 读写锁具体实例:
/*
* rwlock.c
*
* Created on: 2016年11月6日
* Author: chy
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/unistd.h>
#include <sys/errno.h>
#include <sys/shm.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define key 520 //共享存储
#define date_key 521 //共享存储
#define Max 128 //缓冲区最大最
#define Pthread 16 //创建进程个数
#define ERR(msg,f) { \
if(f < 0) { \
fprintf(stderr,"%s",msg); \
exit(1); \
} \
}
struct info{ //描述缓冲区的信息
pid_t id;
pthread_t t;
char data[Max];
};
const char str[][Max] = { //随机选择写入
"曾经沧海难为水",
"除却巫山不是云",
"哈哈哈哈",
"chen",
"hong",
"yu",
};
struct arg{ //封装参数
struct info *data;
pthread_rwlock_t *rwlock;
pthread_t *t;
};
int get_id(const int shm_id) //获取共享存储的描述字
{
int shm_ID;
shm_ID = shmget(shm_id, sizeof(pthread_rwlock_t), 0777 | IPC_CREAT);
ERR("get shm failed\n",shm_ID);
return shm_ID;
}
void *get_shm(const int shm_ID) //链接共享存储
{
void *rwlock = NULL;
rwlock = shmat(shm_ID, NULL, 0);
if(!rwlock)
ERR("link shm failed\n",-1);
return rwlock;
}
void init_rwlock(pthread_rwlock_t *relock) //初始化读写锁
{
pthread_rwlockattr_t attr_t;
ERR("rwlockattr init failed\n", pthread_rwlockattr_init(&attr_t));
ERR("rwlockattr set failed\n", pthread_rwlockattr_setpshared(&attr_t,PTHREAD_PROCESS_SHARED));
ERR("relock init failed\n",pthread_rwlock_init(relock, &attr_t));
ERR("rwlockattr destroy failed\n", pthread_rwlockattr_destroy(&attr_t));
return;
}
void read_data(struct arg *data) //读函数
{
ERR("read lock failed\n",pthread_rwlock_rdlock(data->rwlock));
printf("pid=%d pthread=%lx info:%s\n",data->data->id,data->data->t,data->data->data);
ERR("read unlock falide\n",pthread_rwlock_unlock(data->rwlock));
pthread_exit(NULL);
}
void write_data(struct arg *data) //写函数
{
ERR("write lock failed",pthread_rwlock_wrlock(data->rwlock));
strcpy(data->data->data,str[rand()%6]);
data->data->t = pthread_self();
data->data->id = getpid();
printf("this is write,pid=%d pthread=%lx data:%s\n",data->data->id,data->data->t,data->data->data);
ERR("write ublick failed\n",pthread_rwlock_unlock(data->rwlock));
pthread_exit(NULL);
}
struct arg aa;
int main(int arg,char *argv[])
{
aa.t = malloc(sizeof(pthread_t) * Pthread); //给线程描述字分配信息
int shm_rw;
shm_rw = get_id(key); //获得共存储描述字
aa.rwlock = (pthread_rwlock_t *)get_shm(shm_rw); //链接共享存储
if(!aa.rwlock)
ERR("create shm falied\n",-1);
init_rwlock(aa.rwlock); //初始化读写锁
int shm_date;
shm_date = get_id(date_key); //获得共享存储描述字
aa.data = (struct info*)get_shm(shm_date); //链接共享存储
int i;
for(i = 0; i < Pthread; i++){
if((i%2)){
ERR("cteart write faile",pthread_create((pthread_t*)&aa.t[i], NULL,(void* (*)())read_data,(void*)&aa)); //创建读线程
}
else{
ERR("cteart write faile",pthread_create((pthread_t*)&aa.t[i], NULL,(void* (*)()) write_data, (void*)&aa)); //创建写线程
}
}
for(i = 0; i < Pthread; i++) //等待所有线程结束
pthread_join(aa.t[i],NULL);
shmctl(shm_rw, IPC_RMID, NULL); //删除共享存储
shmctl(shm_date, IPC_RMID, NULL); //删除共享存储
exit(0);
}
3. 条件变量
3.1 条件变量的初始化和销毁
#include <pthrad.h>
pthread_cond_t = PTHREAD_COND_INITIALIZER; //静态变量初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); //初始化变量
int pthread_cond_destroy(pthread_cond_t *cond); //销毁
3.2 条件变量属性的初始化、销毁、设置和获取
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr); //初始化条件变量
int pthread_condattr_destroy(pthread_condattr_t *attr); //销毁条件变量
int pthread_condattr_setpshared(pthread_condattr_t *attr,int *pshared); //设置条件变量
int pthread_condattr_getpshared(pthread_condattr_t *attr,int *pshared); //获取条件变量
3.3 等待条件变量
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); //等待条件变量
int pthread_cond_timewait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime); //等待条件变量,超时错误返回
3.4 唤醒正在等待的条件变量
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t (cond); //唤醒一个
int pthread_cond_broadcast(pthread_cond_t (cond); //唤醒全部
3.5 条件变量具体实例
/*
* cond.c
*
* Created on: 2016年11月14日
* Author: chy
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/unistd.h>
#include <sys/signal.h>
#include <pthread.h>
#define Pthread_P_C 2 //生产、消费的个数
#define ERR(msg,f){ \
if(f < 0){ \
fprintf(stderr,"%s",msg); \
exit(-1); \
} \
}
struct arg{ //信息描述
pthread_t *t_id;
pthread_cond_t cond;
pthread_mutex_t mutex;
int shop;
};
void consum(void *temp) //生产者
{
while(1){
pthread_mutex_lock(&((struct arg*)temp)->mutex); //获取互斥变量
while(!((struct arg*)temp)->shop){
printf("consum_pthread_t=%ld waiting\n",pthread_self());
pthread_cond_wait(&((struct arg*)temp)->cond,&((struct arg*)temp)->mutex); //没有商品则等待
}
printf("pthread_t=%ld start shoping\n",pthread_self());
((struct arg*)temp)->shop--;
printf("pthread_t=%ld end shoping\n",pthread_self());
pthread_mutex_unlock(&((struct arg*)temp)->mutex); //释放互斥变量
sleep(1);
}
}
void production(void *temp)
{
while(1){
pthread_mutex_lock(&((struct arg*)temp)->mutex); //获取互斥变量
printf("pthread_t=%ld start production\n",pthread_self());
((struct arg*)temp)->shop++;
printf("pthread_t=%ld end production\n",pthread_self());
printf("produc_pthread_t=%ld sending\n",pthread_self());
pthread_cond_signal(&((struct arg*)temp)->cond); //唤醒等待线程
pthread_mutex_unlock(&((struct arg*)temp)->mutex); //释放互斥变量
sleep(1);
}
}
struct arg dat = { //初始化描述信息
.shop = 0,
};
void signal_func(int sig) //句柄函数
{
kill(getpid(),SIGKILL);
}
int main(int argc,char *argv[])
{
sigset_t set;
sigemptyset(&set);
struct sigaction sig = {
.sa_handler = signal_func,
.sa_mask = set,
};
struct sigaction old_sig;
sigaction(SIGINT,&sig,&old_sig); //设置句柄函数
pthread_mutex_init(&dat.mutex,NULL); //初始化互斥变量
pthread_cond_init(&dat.cond,NULL); //初始化条件变量
dat.t_id = (pthread_t*)malloc(sizeof(pthread_t) * Pthread_P_C * 2);
int i;
for(i = 0; i < Pthread_P_C; i++){ //创建消费者线程
ERR("create_p faile\n",pthread_create(&dat.t_id[i],NULL,(void* (*)())consum,(void*)&dat));
}
for(; i < Pthread_P_C * 2; i++){ //创建生产者线程
ERR("create_p faile\n",pthread_create(&dat.t_id[i],NULL,(void* (*)())production,(void*)&dat));
}
for(i = 0; i < Pthread_P_C * 2; i++) //等待线程全部结束
pthread_join(dat.t_id[i],NULL);
sigaction(SIGINT,&old_sig,NULL); //恢复信号的默认动作
pthread_mutex_destroy(&dat.mutex); //销毁互斥变量
pthread_cond_destroy(&dat.cond); //销毁条件变量
exit(0);
}