这应该是最后一次,还是认认真真滴完成。
本次内容围绕一个问题,线程并发时对于全局变量会错位控制。所以必须加以限制,限制的手段有两种:条件变量、互斥信号量。
一、条件变量
条件变量的操作就三个:初始化、等待、唤醒线程。具体的用法如下:
有了条件变量,就可以在全局变量前面加上。线程并发时就会在执行前获取条件变量的情况了。
二、互斥信号量
信号量的使用是通过锁来实现的,所以信号量的操作包括初始化、上锁、解锁。具体如下:
其实我觉得二者没有什么区别,完成的功能都一样。而且在理论课上只讲了信号量,没有提及条件变量。所以可能各有所好吧,我就不知道啦~
老规矩,还是有作业。是解决一个经典的生产者-消费者问题,做了一点儿拓展,加了一个计算者。题目如下:
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define CAPACITY 4
int buffer1[CAPACITY];
int buffer2[CAPACITY];
int in1;
int out1;
int in2;
int out2;
int buffer1_is_empty()
{
return in1 == out1;
}
int buffer1_is_full()
{
return (in1 + 1) % CAPACITY == out1;
}
int buffer2_is_empty()
{
return in2 == out2;
}
int buffer2_is_full()
{
return (in2 + 1) % CAPACITY == out2;
}
// buffer1操作,操作变量是out1,in1
int get_item1()
{
int item;
item = buffer1[out1];
out1 = (out1 + 1) % CAPACITY;
return item;
}
void put_item1(int item)
{
buffer1[in1] = item;
in1 = (in1 + 1) % CAPACITY;
}
// buffer2操作,操作变量是out2,in2
int get_item2()
{
int item;
item = buffer2[out2];
out2 = (out2 + 1) % CAPACITY;
return item;
}
void put_item2(int item)
{
buffer2[in2] = item;
in2 = (in2 + 1) % CAPACITY;
}
pthread_mutex_t mutex;
pthread_cond_t wait_empty_buffer1;
pthread_cond_t wait_full_buffer1;
pthread_cond_t wait_empty_buffer2;
pthread_cond_t wait_full_buffer2;
#define ITEM_COUNT (CAPACITY * 2)
// consume对于buffer2是消费者
void *consume(void *arg)
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
pthread_mutex_lock(&mutex);
while (buffer2_is_empty())
pthread_cond_wait(&wait_full_buffer2, &mutex);
item = get_item2();
printf(" consume item: %c\n", item);
pthread_cond_signal(&wait_empty_buffer2);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
// produce对于buffer1是生产者
void *produce(void *arg)
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
pthread_mutex_lock(&mutex);
while (buffer1_is_full())
pthread_cond_wait(&wait_empty_buffer1, &mutex);
item = 'a' + i;
put_item1(item);
printf("produce item: %c\n", item);
pthread_cond_signal(&wait_full_buffer1);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
/*calculate对于buffer1是消费者,对于buffer2是生产者*/
void *calculate(void *arg)
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
// buffer1操作
pthread_mutex_lock(&mutex);
while (buffer1_is_empty())
pthread_cond_wait(&wait_full_buffer1, &mutex);
item = get_item1();
item = item-32; // 完成计算者功能
pthread_cond_signal(&wait_empty_buffer1);
pthread_mutex_unlock(&mutex);
// buffer2操作
pthread_mutex_lock(&mutex);
while(buffer2_is_full())
pthread_cond_wait(&wait_empty_buffer2, &mutex);
put_item2(item);
pthread_cond_signal(&wait_full_buffer2);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
pthread_t consumer_tid;
pthread_t calculator_tid;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&wait_empty_buffer1, NULL);
pthread_cond_init(&wait_full_buffer1, NULL);
pthread_cond_init(&wait_empty_buffer2, NULL);
pthread_cond_init(&wait_full_buffer2, NULL);
pthread_create(&calculator_tid, NULL, calculate, NULL);
pthread_create(&consumer_tid, NULL, consume, NULL);
produce(NULL);
// 此处一定要写线程等待,因为生产者最先结束,不写主进程会随之结束
pthread_join(calculator_tid, NULL);
pthread_join(consumer_tid, NULL);
return 0;
}
代码如下:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#define CAPACITY 4
int buffer1[CAPACITY];
int in1;
int out1;
int buffer2[CAPACITY];
int in2;
int out2;
// 定义buffer1操作,操作对象为in1,out1
int buffer1_is_empty()
{
return in1 == out1;
}
int buffer1_is_full1()
{
return (in1 + 1) % CAPACITY == out1;
}
// 定义buffer2操作,操作对象为in2,ou2
int buffer2_is_empty()
{
return in2 == out2;
}
int buffer2_is_full1()
{
return (in2 + 1) % CAPACITY == out2;
}
// buffer1数据相关
int get_item1()
{
int item;
item = buffer1[out1];
out1 = (out1 + 1) % CAPACITY;
return item;
}
void put_item1(int item)
{
buffer1[in1] = item;
in1 = (in1 + 1) % CAPACITY;
}
// buffer2数据相关
int get_item2()
{
int item;
item = buffer2[out2];
out2 = (out2 + 1) % CAPACITY;
return item;
}
void put_item2(int item)
{
buffer2[in2] = item;
in2 = (in2 + 1) % CAPACITY;
}
typedef struct {
int value;
pthread_mutex_t mutex;
pthread_cond_t cond;
} sema_t;
// 信号量操作是统一的,不需要单独设定
void sema_init(sema_t *sema, int value)
{
sema->value = value;
pthread_mutex_init(&sema->mutex, NULL);
pthread_cond_init(&sema->cond, NULL);
}
void sema_wait(sema_t *sema)
{
pthread_mutex_lock(&sema->mutex);
while (sema->value <= 0)
pthread_cond_wait(&sema->cond, &sema->mutex);
sema->value--;
pthread_mutex_unlock(&sema->mutex);
}
void sema_signal(sema_t *sema)
{
pthread_mutex_lock(&sema->mutex);
++sema->value;
pthread_cond_signal(&sema->cond);
pthread_mutex_unlock(&sema->mutex);
}
sema_t mutex_sema;
sema_t empty_buffer1_sema;
sema_t full_buffer1_sema;
sema_t empty_buffer2_sema;
sema_t full_buffer2_sema;
#define ITEM_COUNT (CAPACITY * 2)
// consume是buffer2数组的消费者
void *consume(void *arg)
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
sema_wait(&full_buffer2_sema);
sema_wait(&mutex_sema);
item = get_item2();
printf(" consume item: %c\n", item);
sema_signal(&mutex_sema);
sema_signal(&empty_buffer2_sema);
}
return NULL;
}
// produce是buffer1数组的生产者
void *produce()
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
sema_wait(&empty_buffer1_sema);
sema_wait(&mutex_sema);
item = i + 'a';
put_item1(item);
printf("produce item: %c\n", item);
sema_signal(&mutex_sema);
sema_signal(&full_buffer1_sema);
}
return NULL;
}
// calculate是buffer1数组的消费者,buffer2数组的生产者
void *calculate()
{
int i;
int item;
for (i = 0; i < ITEM_COUNT; i++) {
// buffer1相关操作
sema_wait(&full_buffer1_sema);
sema_wait(&mutex_sema);
item = get_item1();
item = item - 32;
sema_signal(&mutex_sema);
sema_signal(&empty_buffer1_sema);
// buffer2相关操作
sema_wait(&empty_buffer2_sema);
sema_wait(&mutex_sema);
put_item2(item);
sema_signal(&mutex_sema);
sema_signal(&full_buffer2_sema);
}
return NULL;
}
int main()
{
pthread_t consumer_tid;
pthread_t calculator_tid;
sema_init(&mutex_sema, 1);
sema_init(&empty_buffer1_sema, CAPACITY - 1);
sema_init(&full_buffer1_sema, 0);
sema_init(&empty_buffer2_sema, CAPACITY - 1);
sema_init(&full_buffer2_sema, 0);
pthread_create(&consumer_tid, NULL, consume, NULL);
pthread_create(&calculator_tid, NULL, calculate, NULL);
// 必须线程等待,生产者会先完成,不写提前结束主函数
produce();
pthread_join(consumer_tid, NULL);
pthread_join(calculator_tid, NULL);
return 0;
}
因作者水平有限,如有错误之处,请在下方评论区指出,谢谢!