信号量:
应用于线程、进程间同步。
相当于 初始化值为 N 的互斥量。 N值,表示可用资源数, 可以同时访问共享数据区的线程数。
函数:
sem_t sem; 定义类型。
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem: 信号量
pshared: 0: 用于线程间同步
1: 用于进程间同步
value:N值。(表示可用资源数)
sem_destroy();
sem_wait(); 一次调用,做一次-- 操作, 当信号量的值为 0 时,再次 -- 就会阻塞。 (对比 pthread_mutex_lock)
sem_post(); 一次调用,做一次++ 操作. 当信号量的值为 N 时, 再次 ++ 就会阻塞。(对比 pthread_mutex_unlock)
使用mutex(互斥量、互斥锁)一般步骤:
pthread_mutex_t 类型。
1. pthread_mutex_t lock; 创建锁
2 pthread_mutex_init; 初始化 1
3. pthread_mutex_lock;加锁 1-- --> 0
4. 访问共享数据(stdout)
5. pthrad_mutext_unlock();解锁 0++ --> 1
6. pthead_mutex_destroy;销毁锁
初始化互斥量:
pthread_mutex_t mutex;
1. pthread_mutex_init(&mutex, NULL); 动态初始化。
2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 静态初始化。
注意事项:
尽量保证锁的粒度, 越小越好。(访问共享数据前,加锁。访问结束【立即】解锁。)
互斥锁,本质是结构体。 我们可以看成整数。 初值为 1。(pthread_mutex_init() 函数调用成功。)
加锁: --操作, 阻塞线程。
解锁: ++操作, 换醒阻塞在锁上的线程。
try锁:尝试加锁,成功--。失败,返回。同时设置错误号 EBUSY
/*信号量实现 生产者 消费者问题*/
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define NUM 5
int queue[NUM]; //全局数组实现环形队列
sem_t blank_number, product_number; //空格子信号量, 产品信号量
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
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); //消费者将产品数--,为0则阻塞等待
printf("--Consume---%d, i = %d\n", queue[i], i);
queue[i] = 0; //消费一个产品
i = (i+1) % NUM;
printf("--------i = %d \n", i);
sem_post(&blank_number); //消费掉以后,将空格子数++
sleep(rand()%3);
}
}
int main(int argc, char *argv[])
{
pthread_t pid, cid, cid2;
sem_init(&blank_number, 0, NUM); //初始化空格子信号量为5, 线程间共享 -- 0
sem_init(&product_number, 0, 0); //产品数为0
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_create(&cid2, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
pthread_join(cid2, NULL);
sem_destroy(&blank_number);
sem_destroy(&product_number);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
consumer的i是在栈空间的,属于线程单独的;应该使用全局变量才能同步,要不两个线程的 i 是两个不一样的。
/*信号量实现 生产者 消费者问题*/
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define NUM 5
int queue[NUM]; //全局数组实现环形队列
sem_t blank_number, product_number; //空格子信号量, 产品信号量
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
int k = 0;
int i = 0;
void *producer(void *arg)
{
while (1) {
sem_wait(&blank_number); //生产者将空格子数--,为0则阻塞等待
pthread_mutex_lock(&mutex1);
queue[i] = rand() % 1000 + 1; //生产一个产品
printf("----Produce---%d\n", queue[i]);
pthread_mutex_unlock(&mutex1);
sem_post(&product_number); //将产品数++
i = (i+1) % NUM; //借助下标实现环形
sleep(rand()%1);
}
}
void *consumer(void *arg)
{
while (1) {
sem_wait(&product_number); //消费者将产品数--,为0则阻塞等待
pthread_mutex_lock(&mutex1);
printf("--Consume---%d, k = %d\n", queue[k], k);
queue[k] = 0; //消费一个产品
k = (k+1) % NUM;
printf("--------k = %d \n", k);
pthread_mutex_unlock(&mutex1);
sem_post(&blank_number); //消费掉以后,将空格子数++
// sleep(rand()%3);
}
}
int main(int argc, char *argv[])
{
pthread_t pid, cid, cid2;
sem_init(&blank_number, 0, NUM); //初始化空格子信号量为5, 线程间共享 -- 0
sem_init(&product_number, 0, 0); //产品数为0
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_create(&cid2, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
pthread_join(cid2, NULL);
sem_destroy(&blank_number);
sem_destroy(&product_number);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}