进程同步问题

目录

生产者消费者模型

读者作者模型

总结


生产者消费者模型

问题描述

  • 当缓冲区满时,生产者不能进入临界区生产(同步)
  • 当缓冲区空时,消费者不能进入临界区消费(同步)
  • 由于只考虑了一个生产者,一个消费者,互斥问题不存在

原型

方法--声明一个长度为 n 的数组,但只能使用其中 n-1 个空间

缺点--n个空间没有用完;忙等待

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>    /*srand*/
#include<unistd.h>    /*sleep*/

#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

void *producer(void *arg){
    while(1){
        while(((in + 1)%BUFFER_SIZE)==out){
            // 缓冲区已满
            printf("full\n");
            sleep(1);
        }
        int item = rand() % 10;
        buffer[in] = item;
        printf("producing an item %d......\n", item);
        in = (in + 1) % BUFFER_SIZE;
        sleep(1);
    }
}

void *consumer(void *arg){
    while(1){
        while(in == out){
            // 缓冲区为空
            printf("empty\n");
            sleep(1);
        }
        int item = buffer[out];
        printf("\t\t\t\tconsuming an item %d......\n", item);
        out = (out + 1) % BUFFER_SIZE;
        sleep(1);
    }
}

int main(){
    srand((unsigned)time(NULL));
    pthread_t tid_producer, tid_consumer;
    pthread_create(&tid_producer, 0, producer, NULL);
    pthread_create(&tid_consumer, 0, consumer, NULL);
    pthread_join(tid_producer, NULL);
    pthread_join(tid_consumer, NULL);
    return 0;
}

第一次尝试

方法--用一个变量 counter 来计数

缺点--race

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int counter = 0;

void *producer(void *arg){
    while(1){
        while(counter == BUFFER_SIZE){
            // 缓冲区已满
            printf("full\n");
            sleep(1);
        }
        int item = rand() % 10;
        buffer[in] = item;
        printf("producing an item %d......\n", item);
        in = (in + 1) % BUFFER_SIZE;
        counter++;
        sleep(1);
    }
}

void *consumer(void *arg){
    while(1){
        while(counter == 0){
            // 缓冲区为空
            printf("empty\n");
            sleep(1);
        }
        int item = buffer[out];
        printf("\t\t\t\tconsuming an item %d......\n", item);
        out = (out + 1) % BUFFER_SIZE;
        counter--;    
        sleep(1);
    }
}

int main(){
    srand((unsigned)time(NULL));
    pthread_t tid_producer, tid_consumer;
    pthread_create(&tid_producer, 0, producer, NULL);
    pthread_create(&tid_consumer, 0, consumer, NULL);
    pthread_join(tid_producer, NULL);
    pthread_join(tid_consumer, NULL);
    return 0;
}

第二次尝试

方法--信号量解决同步问题

#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<unistd.h>  
#include<stdlib.h>  

#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];    // 共享变量
int in = 0;
int out = 0;
sem_t empty, full, mutex;


void *producer(void *arg){
    while(1){
        int item = rand() % 10;
        sem_wait(&empty);
        sem_wait(&mutex);
        buffer[in] = item;
        printf("producing an item %d......\n", item);
        sem_post(&mutex);
        sem_post(&full);    
        in = (in + 1) % BUFFER_SIZE;
        
        sleep(1);
    }
}

void *consumer(void *arg){
    while(1){
        sem_wait(&full);
        sem_wait(&mutex);
        int item = buffer[out];
        printf("\t\t\t\tconsuming an item %d......\n", item);
        sem_post(&mutex);
        sem_post(&empty);
        out = (out + 1) % BUFFER_SIZE;
        sleep(1);
    }
}

int main(){
    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);
    sem_init(&mutex, 0, 1);
    srand((unsigned)time(NULL));
    pthread_t tid_producer, tid_consumer;
    pthread_create(&tid_producer, 0, producer, NULL);
    pthread_create(&tid_consumer, 0, consumer, NULL);
    pthread_join(tid_producer, NULL);
    pthread_join(tid_consumer, NULL);
    sem_destroy(&empty);
    sem_destroy(&full);
    sem_destroy(&mutex);
    return 0;
}

读者作者模型

问题描述

  • 某一时刻,可以有多个读者进入临界区阅读(同步)
  • 某一时刻,有且仅有一个作家能够进入临界区写作(同步)
  • 某一时刻,当有作家在临界区内写作,读者不能进入临界区阅读(互斥)
  • 某一时刻,当有读者在临界区内阅读,或有其他作家在临界区内写作,作家不能进入临界区写作(互斥)

原型

缺点--同步问题和互斥问题都没有解决。

#include<pthread.h>
#include<stdio.h>
#include<unistd.h>  /*sleep*/

void *writer(void *arg){
    while(1){
        /* critical section */
        printf("\t\t\t\twriting is performed......\n");
        sleep(1);
    }
}

void *reader(void *arg){
    while(1){      
        /* critical section */
        printf("reading is performed......\n");
        sleep(1);
    }
}

int main(){
    pthread_t tid_writer[2], tid_reader[5];
    for(int i = 0; i < 2; i++){
        pthread_create(&tid_writer[i], NULL, writer, NULL);
    }
    for(int j = 0; j < 3; j++){
        pthread_create(&tid_reader[j], NULL, reader, NULL);
    }
    for(int i = 0; i < 2; i++){
        pthread_join(tid_writer[i], NULL);
    }
    for(int j = 0; j < 3; j++){
        pthread_join(tid_reader[j], NULL);
    }
    return 0;
}

第一次尝试

方法--声明一个信号量rw_mutex解决同步问题和互斥问题

缺点--

  1. 读者的同步问题没有完全解决

    考虑以下情形:

    作者进入临界区写作,此时,有大批读者在等待进入临界区(卡在sem_wait处)。

    当作者退出临界区时,卡在临界区外的读者(不考虑新来的读者)只有一个能够进入临界区,违背同步。

  2. 引入了另一个共享变量read_count,但没有进行保护

分析错误原因--允许多个读者执行执行P操作(sem_init),实际上只需要第一个读者执行P操作

#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<unistd.h>

int read_count = 0;
sem_t rw_mutex;

void *writer(void *arg){
    while(1){
        sem_wait(&rw_mutex);
        /* critical section */
        printf("\t\t\t\twriting is performed......\n");
        sem_post(&rw_mutex);
        sleep(1);
    }
}

void *reader(void *arg){
    while(1){
        if(read_count == 0){
            sem_wait(&rw_mutex);
        }
        read_count++;
        /* critical section */
        printf("reading is performed......\n");
        read_count--;
        if(read_count == 0){
            sem_post(&rw_mutex);
        }
        sleep(1);
    }
}

int main(){
    sem_init(&rw_mutex, 0, 1);
    pthread_t tid_writer[2], tid_reader[5];
    for(int i = 0; i < 2; i++){
        pthread_create(&tid_writer[i], NULL, writer, NULL);
    }   
    for(int j = 0; j < 3; j++){
        pthread_create(&tid_reader[j], NULL, reader, NULL);
    }
    for(int i = 0; i < 2; i++){
        pthread_join(tid_writer[i], NULL);
    }
    for(int j = 0; j < 3; j++){
        pthread_join(tid_reader[j], NULL);
    }
    sem_destroy(&rw_mutex);
    return 0;
}

第二次尝试

方法--声明另一个信号量mutex,只允许一个读者进行P操作(sem_init),同时保护共享变量read_count

#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<unistd.h>

int read_count = 0;
sem_t rw_mutex;
sem_t mutex;

void *writer(void *arg){
    while(1){
        sem_wait(&rw_mutex);
        /* critical section */
        printf("\t\t\t\twriting is performed......\n");
        sem_post(&rw_mutex);
        sleep(1);
    }
}

void *reader(void *arg){
    while(1){
        sem_wait(&mutex);
        if(read_count == 0){
            sem_wait(&rw_mutex);
        }
        read_count++;
        sem_post(&mutex);
        /* critical section */
        printf("reading is performed......\n");
        sem_wait(&mutex);
        read_count--;
        if(read_count == 0){
            sem_post(&rw_mutex);
        }
        sem_post(&mutex);
        sleep(1);
    }
}

int main(){
    sem_init(&rw_mutex, 0, 1);
    sem_init(&mutex, 0, 1);
    pthread_t tid_writer[2], tid_reader[5];
    for(int i = 0; i < 2; i++){
        pthread_create(&tid_writer[i], NULL, writer, NULL);
    }
    for(int j = 0; j < 3; j++){
        pthread_create(&tid_reader[j], NULL, reader, NULL);
    }
    for(int i = 0; i < 2; i++){
        pthread_join(tid_writer[i], NULL);
    }
    for(int j = 0; j < 3; j++){
        pthread_join(tid_reader[j], NULL);
    }
    sem_destroy(&rw_mutex);
    sem_destroy(&mutex);
    return 0;
}

总结

  • 协作进程需要解决通信和同步问题。
  • 通信可以通过共享内存和消息传递(比如管道、套接字、远程过程调用)的方式。
  • 同步问题一般通过信号量的方式解决。
  • 同步问题有时伴随着互斥问题,一般来说,同步比互斥更加困难,在考虑同步和互斥问题时,优先解决同步,再解决互斥。
  • 即使有了信号量这个工具,解决同步问题仍然是很棘手的,通过调试的方式几乎不能发现错误,只能通过严密的逻辑思考去尽可能减少错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值