一、线程同步 条件变量 什么是条件变量? 线程A等待某个条件成立,条件成立,线程A才继续向下执行。线程B的执行使条件成立,条件成立以后唤醒线程A,以继续执行。这个条件就是条件变量。 pthread_cond_t 类型 就是条件变量的类型 对类型的封装如下: #include <pthread.h> //条件变量的静态初始化 pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); 功能:初始化一个条件变量 参数: cond:指定要初始化的条件变量 cond_attr:NULL 默认属性 返回值: 0 成功 非0 错误 int pthread_cond_signal(pthread_cond_t *cond); 功能:启动在等待条件变量变为真的一个线程 参数: cond:指定条件变量 返回值: 0 成功 非0 错误 int pthread_cond_broadcast(pthread_cond_t *cond); 功能:启动所有的等待条件变量为真的线程 参数: cond:指定条件变量 返回值: 0 成功 非0 错误 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 功能:等待条件变量为真 参数: cond:指定等待的条件变量 mutex:等待之前需要解开的锁 返回值: 0 成功 非0 错误 操作步骤: 1、先原子解mutex锁。 2、让线程等待条件变量变为真。 3、条件变量为真的时候,加锁 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); 功能:超时等待,超时返回错误 参数: cond:指定等待的条件变量 mutex:等待之前需要解开的锁 abstime:指定等待的时间 返回值: 0 成功 非0 错误 int pthread_cond_destroy(pthread_cond_t *cond); 功能:销毁条件变量 参数: cond:指定要销毁的条件变量 返回值: 0 成功 非0 错误 生产者和消费者的例子 链表实现 生产者生产出来对象放到链表的头部 消费者从链表的头部取出消费。 第一思考:两个线程如何同步访问链表的头部 第二思考:如果链表为空,消费者等待生产者线程生产对象。 第三思考:生产者线程,生产出对象通知消费者。 代码参见: cond.c 信号量 多个线程使用多个资源的时候,使用信号量实现线程的同步。 sem_t类型 类型的操作如下: sem_init(3) #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); 功能:初始化信号量 参数: sem:指定了要初始化的信号量 pshared:0 应用于多线程 非0 多进程 value:指定了信号量的初始值 返回值: 0 成功 -1 失败 errno被设置 sem_destroy(3) #include <semaphore.h> int sem_destroy(sem_t *sem); 功能:销毁信号量 参数: sem:指定要销毁的信号量 返回值: 0 成功 -1 错误 errno被设置 sem_post(3) #include <semaphore.h> int sem_post(sem_t *sem); 功能:信号量的值加1操作 参数: sem:指定的信号量,就是这个信号量的值加1. 返回值: 0 成功 -1 错误 errno被设置 sem_wait(3) #include <semaphore.h> int sem_wait(sem_t *sem); 功能:信号量的值减1.如果信号量的值为0.阻塞等待 参数: sem:指定了要操作的信号量 返回值: 0 成功 -1 错误 errno被设置 int sem_trywait(sem_t *sem); int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 使用信号量,实现生产者和消费者的例子 使用环状队列实现。 代码参见 sem.c 线程结束了 二、system v IPC 信号量集 信号量集就是数组,数组里的每一个元素都是信号量类型的。 1、先获取键值 ftok(3) 2、使用键值获取信号量集的id semget(2) #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); 功能:获取信号量集的id 参数: key:ftok(3)的返回值 nsems:指定了信号量集中的元素个数 semflg: IPC_CREAT: IPC_EXCL: mode:指定信号量集的权限 返回值: 非负整数,是信号量集的id。 -1 错误 errno被设置 3、设置信号量集中的信号量的初值或者获取信号量的值。 semctl(2) #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl(int semid, int semnum, int cmd, ...); 功能:信号量的控制操作 参数: semid:指定了信号量集 semnum:指定了信号量在数组中的下标 cmd:指定了对信号量的控制操作命令 GETVAL:获取到第几个信号了的semval值。 semval的值 SETVAL:设置第几个信号量的semval值为arg.val。 0 ...:可变参数。这个有没有,什么类型?取决于cmd。 返回值: -1 错误 errno被设置 需要自定义 union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT,IPC_SET */ unsigned short *array; /*Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ }; 4、对指定的信号量加法或者减法操作 semop(2) #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semop(int semid, struct sembuf *sops, unsigned nsops); 功能:信号量操作 参数: semid:指定了信号量集 sops:指定了对某个信号量的具体操作 nsops:指定了要操作的信号量的个数。 返回值: 0 成功 -1 错误 errno被设置 操作定义在这个结构体中 struct sembuf{ unsigned short sem_num; /* semaphore number */ short sem_op; /* semaphore operation */ short sem_flg; /* operation flags */ }; sem_flg: IPC_NOWAIT IPC_UNDONE 自动撤销操作 sem_num:指定了要操作的信号量在数组的下标 sem_op:指定了操作的类型 操作类型分为3种 >0 semval+sem_op semval做加法 =0 <0: semval>sem_op的绝对值,这个操作立即执行。 semval<sem_op的绝对值 申请的资源数>可用资源数 IPC_NOWAIT 非阻塞 sem_flg=0 阻塞等待资源可用 举例说明 使用信号量集实现进程间的通讯。 两个进程 PA.c 设置信号量的值 ,每隔3秒,semval的值减1 Pb.c 每隔1秒,获取信号量的值,