操作系统实践(九)

  这应该是最后一次,还是认认真真滴完成。
  本次内容围绕一个问题,线程并发时对于全局变量会错位控制。所以必须加以限制,限制的手段有两种:条件变量、互斥信号量。

   一、条件变量

  条件变量的操作就三个:初始化、等待、唤醒线程。具体的用法如下:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
  有了条件变量,就可以在全局变量前面加上。线程并发时就会在执行前获取条件变量的情况了。

   二、互斥信号量

  信号量的使用是通过锁来实现的,所以信号量的操作包括初始化、上锁、解锁。具体如下:
在这里插入图片描述在这里插入图片描述
   其实我觉得二者没有什么区别,完成的功能都一样。而且在理论课上只讲了信号量,没有提及条件变量。所以可能各有所好吧,我就不知道啦~

  老规矩,还是有作业。是解决一个经典的生产者-消费者问题,做了一点儿拓展,加了一个计算者。题目如下:
在这里插入图片描述
  代码如下:

#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;
}

因作者水平有限,如有错误之处,请在下方评论区指出,谢谢!

Guess you like

Origin blog.csdn.net/gls_nuaa/article/details/117953722