精华内容
下载资源
问答
  • 进程同步与互斥

    2013-12-19 10:17:14
    有关于进程同步互斥的C语言实现,希望对你们有帮助!
  • 进程同步与互斥 实验原理 (1)同步和互斥(生产者消费者问题) 同步是一种更为复杂的互斥,而互斥是一种特殊的同步。 互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制...

    C语言实现进程同步与互斥

    实验原理

    (1)同步和互斥(生产者消费者问题)
    同步是一种更为复杂的互斥,而互斥是一种特殊的同步。
    互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

    同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
    (2)信号量
    在系统中,给予每一个进程一个信号量,代表每个进程目前的状态,未得到控制权的进程会在特定地方被强迫停下来,等待可以继续进行的信号到来。信号量又存在着两种操作,分别为V操作与P操作,V操作会增加信号量 S的数值,P操作会减少它。
    (3)锁
    在多线程编程中,操作系统引入了锁机制。通过锁机制,能够保证在多核多线程环境中,在某一个时间点上,只能有一个线程进入临界区代码,从而保证临界区中操作数据的一致性。
    加锁过程用如下伪码表示:
    1、read lock;
    2、判断lock状态;(0表示资源可用,1表示资源已被占用)
    3、如果已经加锁,失败返回;
    4、把锁状态设置为上锁;
    5、返回成功。

    实验内容和方法

    1.实验一(进程同步):
    1)实验内容
    分别创建两个工程,用来scanf和printf,从键盘输入,在屏幕上显示输入了多少个数,以此来实现进程同步。
    2)代码以及代码分析

    Scanf.c

    #include<stdio.h>
    #include<windows.h>
    int main(){
    		HANDLE h;
    		int a=0;
    		h=CreateSemaphore(NULL,0,10,"scanfcount");
    		while(1)
    		{
    			scanf("%d",&a);
    			printf("%d",a);
    			ReleaseSemaphore(h,1,NULL);
    		}
    }
    

    Printf.c

    #include<stdio.h>
    #include<windows.h>
    int main(){
    		HANDLE h;
    	int count=0;
    	h=CreateSemaphore(NULL,0,10,"scanfcount");
    	
    	while(1)
    	{
    			WaitForSingleObject(h,INFINITE);
    			count++;
    		printf("%d",count);
    
    	
    	}
    }
    

    3)实验结果截图
    每当我在scanf窗口输入一个数,printf窗口的计数器就加1。
    2.实验二(进程互斥):
    1)实验内容
    本次实验中,模拟两个线程实现信号量的争夺(无序性)。通过加锁实现在某一个时间点上,只能有一个线程进入临界区代码,从而保证临界区中操作数据的一致性。
    2)代码及代码分析

    MultiThread.c

    #include<stdio.h>
    #include<windows.h>
    HANDLE m_hMutex; 
    //线程1
    DWORD WINAPI ThreadFunc1(LPVOID lpParam)
    {
    	int i;
    	for(i=0;i<5;i++)
    	{
    				WaitForSingleObject(m_hMutex,INFINITE);//进入临界区域
    		printf("Thread1 step1 in the critical section\n");
    		printf("Thread1 step2 in the critical section\n");
    		ReleaseMutex(m_hMutex);//释放
    	}
        return 0;
    }
    //线程2
    DWORD WINAPI ThreadFunc2(LPVOID lpParam)
    {
    	int i;
    	for(i=0;i<5;i++)
    	{
    		WaitForSingleObject(m_hMutex,INFINITE);
    		printf("Thread2 step1 int the critical section\n");
    		printf("Thread2 step2 inthe critical section\n");
    		ReleaseMutex(m_hMutex);
    	}
        return 0;
    }
    void main()
    {
    	char c;
    	m_hMutex=CreateMutex(NULL,FALSE,NULL);
    	CreateThread(NULL, 0, ThreadFunc1, 0, 0, 0);
    	CreateThread(NULL, 0, ThreadFunc2, 0, 0, 0);
    	scanf("%c\n",&c);
    }
    

    3)实验结果截图

    展开全文
  • 进程同步与互斥实验

    2020-11-04 17:53:18
    进程同步与互斥实验 #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> #define true 1 //生产者ID int product_id = 0; //消费者ID int consumer_id = 0;...

    进程同步与互斥实验

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <stdlib.h>
    #define true 1
    //生产者ID
    int product_id = 0;
    //消费者ID
    int consumer_id = 0;
    //缓冲区大小
    int N;
    //生产者数目
    int producerNum;
    //消费者数目
    int consumerNum;
    //类型定义 int型 信号
    typedef int semaphore;
    //类型定义 int型 商品
    typedef int item;
    //定义 商品类型的缓冲数组
    item* buffer;
    //头索引,输入索引,头指针,用于标识生产者的输入位置
    int in = 0;
    //尾索引,输出索引,尾指针,用于标识消费者的输出位置
    int out = 0;
    //产品数目
    int proCount = 0;
    //mutex 互斥变量,empty 缓冲区空白大小,full 缓冲区非空白大小,proCmutex 生产者互斥变量
    semaphore mutex = 1, empty , full = 0, proCmutex = 1;
    //pthread_create函数创建进程时,需要一个指针类型的函数作为参数,所以定义为指针类型。
    //producer与consumer作为线程的执行体。
    void * producer(void * a){
    int id = ++product_id;
    while(true){
    int flag = 0;
    //如果缓冲区已满报错
    while(empty <= 0){
    printf(“生产者%d:缓冲区已满!阻塞中……\n”,id);
    flag =1;
    sleep(1);
    }
    if(flag ==1)
    printf(“生产者%d因缓冲区有空位唤醒!\n”,id);
    //如果有其他生产者占用进程则互斥,检查有没有其他生产者生产产品
    flag = 0;
    while(proCmutex <= 0){printf(“生产者%d生产阻塞中……\n”,id);flag = 1;sleep(1);};
    //将互斥变量置0,代表已占用
    proCmutex–;
    if(flag == 1)
    printf(“生产者%d生产唤醒!\n”,id);
    //产品号+1
    proCount++;
    printf(“生产者%d:生产一个产品ID%d!\n”,id,proCount);

        //总互斥变量,检查有没有其他进程修改缓冲区数据
        flag = 0;
        while(mutex <= 0){printf("生产者%d装入阻塞中……\n",id);sleep(1);flag=1;};
        //占用进程
        mutex--;
    
        if(flag == 1)
            printf("生产者%d装入唤醒,装入产品ID%d,缓冲区位置为%d!\n",id,proCount,in);
        else
            printf("生产者%d装入产品ID%d,缓冲区位置为%d!\n",id,proCount,in);
        //否则缓冲区空白大小-1
        empty--;
        //缓冲区头指针放入产品
        buffer[in] = proCount;
        //头指针+1
        in = (in + 1) % N;
    
        //缓冲区非空白大小+1
        full++;
        //解除占用
        mutex++;
        //解除生产占用
        proCmutex++;
        //睡一觉
        sleep(1);
    }
    

    }

    void * consumer(void *b){
    int id = ++consumer_id;
    while(true){
    int flag = 0;
    while(full <= 0){
    printf("\t\t\t\t消费者%d:缓冲区为空!阻塞中……\n",id);
    flag = 1;
    sleep(1);
    }
    full–;
    if(flag ==1)
    printf("\t\t\t\t消费者%d因缓冲区有产品唤醒!\n",id);
    flag = 0;

        while(mutex <= 0){printf("\t\t\t\t消费者%d消费阻塞中……\n",id);sleep(1);};
        mutex--;
        if(flag == 1)
            printf("\t\t\t\t消费者%d消费唤醒!\n",id);
        int nextc = buffer[out];
        buffer[out] = 0;//消费完将缓冲区设置为0
        empty++;
        printf("\t\t\t\t消费者%d:消费一个产品ID%d,缓冲区位置为%d\n",id, nextc,out);
        out = (out + 1) % N;
        mutex++;
        sleep(1);
    }
    

    }

    int main()
    {
    int tempnum;
    //输入生产者数目
    printf(“请输入生产者数目:\n”);
    scanf("%d",&tempnum);
    producerNum = tempnum;
    //输入消费者数目
    printf(“请输入消费者数目:\n”);
    scanf("%d",&tempnum);
    consumerNum = tempnum;
    //输入缓冲区大小
    printf(“请输入缓冲区大小:\n”);
    scanf("%d",&tempnum);
    N = tempnum;
    empty = N;
    buffer = (item*)malloc(N*sizeof(item));
    for(int i=0;i<N;i++)
    {
    buffer[i]=0;
    }
    //pthread_t是线程结构,用来保存线程相关数据,可以理解为线程类型,声明线程对象(这里声明的时线程对象数组)
    pthread_t threadPool[producerNum+consumerNum];//声明了线程数组作为线程池
    int i;
    for(i = 0; i < producerNum; i++){
    pthread_t temp;
    //if语句中,第一个参数是线程指针,第二个是线程属性指针,第三个是函数指针,即线程要执行的代码
    //函数通过producer函数指针创建对象,赋值给temp作为线程执行
    if(pthread_create(&temp, NULL, producer, NULL) == -1)
    {
    printf(“ERROR, fail to create producer%d\n”, i);
    exit(1);
    }
    //将temp作为能够执行的线程放入了进程池
    threadPool[i] = temp;
    }//创建生产者进程放入线程池

    //对于消费者进程也同样创建进程
    for(i = 0; i < consumerNum; i++){
        pthread_t temp;
        if(pthread_create(&temp, NULL, consumer, NULL) == -1){
            printf("ERROR, fail to create consumer%d\n", i);
            exit(1);
        }
        threadPool[i+producerNum] = temp;
    }//创建消费者进程放入线程池
    
    
    void * result;
    for(i = 0; i < producerNum+consumerNum; i++){
        //pthread_join函数用与等待线程的结束
        //等待的是子进程的结束,因为如果主进程不等待子进程而直接结束,子进程将没有执行就被杀死。
        if(pthread_join(threadPool[i], &result) == -1){
            printf("fail to recollect\n");
            exit(1);
        }
    }//运行线程池
    return 0;
    

    }

    远哥是真强啊!帅!

    展开全文
  • 第四章 进程同步与互斥 1.进程间的相互作用 识记 与时间有关的错误 进程同步互斥举例 2.进程互斥 领会 临界区 使用临界资源的程序 临界区的使用规则 有空让进 无空等待 多中择一 有限等待 ...

    第四章 进程同步与互斥
        1.进程间的相互作用
            识记
                与时间有关的错误
                进程同步互斥举例
        2.进程互斥
            领会
                临界区
                    使用临界资源的程序
                临界区的使用规则
                    有空让进
                    无空等待
                    多中择一
                    有限等待
                    让权等待
        3.进程同步
            领会
                典型的进程同步例子
                    进程A从硬盘上读记录,每读出一个记录就存入缓冲器。进程B从缓冲器中取出记录加工,直至所有的记录都处理结束
                解决进程同步问题遇到的问题
                    进程A的执行速度超过进程B的执行速度,进程A可能在进程B还没有取走一个记录前,又把新读出的一个记录送人缓冲器,于是后一个记录把上一个尚未取走的记录覆盖了
        4.信号量机制
            综合应用
                信号量和P、V操作的物理含义
                    信号量表示某类可用的临界资源
                    每次P操作意味着请求的进程分配到一个资源;每次V操作,意味着进程释放了一个资源
                用P、V操作解决进程间同步互斥问题
                    进程A
                        P(S);
        临界区操作;
    V(S);
                    进程B
                        P(S);
        临界区操作;
    V(S);
        5.经典的同步互斥问题
            生产者——消费者问题
                P
                    while(true){
        P(empty);
        生产一个产品;
        送产品到缓冲区;
        V(full);
    };
                Q
                    while(true){
        P(full);
        从缓冲区取产品;
        V(empty);
        消费产品;
    };
            读者——写者问题
                读者进程
                    while(true){
        P(mutex);
            read_count = read_count + 1;
            if(read_count = 1) P(write);
        V(mutex);
            读文件;
        P(mutex);
            read_count = read_count - 1;
            if(read_count = 0) V(write);
        V(mutex);
    }
                写者进程
                    while(true){
        P(write);
            写文件;
        V(write);
    }
        6.管程机制
            识记
                管程的概念
                    管程是一个由过程、变量及数据结构等组成的一个集合,它们组成一个特殊的模块或软件包
                管程的组成
                    管程名称
                    共享数据的说明
                    对数据进行操作的一组过程
                    对共享变量赋初值的语句
        7.进程通信
            领会
                共享内存
                    在相互通信的进程之间设有一个公共内存区,一组进程向该公共内存中写,另一组进程从公共区中读
                消息队列
                    进程间的数据交换,是以格式化的消息为单位的。程序员直接利用操作系统提供的一组通信命令,实现大量数据的传递,通信过程对用户是透明的
                信箱机制
                    以发送信件以及接受回答信件为进程间通信的基本方式
                管道
                    连接两个进程之间的一个打开的共享文件,专用于进程之间进行数据通信。发送进程可以源源不断地从管道一端写入数据流,接收进程在需要时可以从管道的另一端读出数据,写入和读出的信息长度都是可变的

    展开全文
  • 经典进程同步与互斥问题

    千次阅读 2019-02-26 17:51:04
    经典进程同步与互斥问题 文章目录经典进程同步与互斥问题一、生产者与消费者问题1.1 问题概述1.2 解决方法二、读者与写者问题2.1 问题概述2.2 解决方法三、哲学家进餐过程3.1 问题概述3.2 解决方法 一、生产者与消费...

    经典进程同步与互斥问题

    一、生产者与消费者问题

    1.1 问题概述

    • 生产者与消费者互斥使用一个缓冲池
    • 当缓冲池为空时,生产者才能写入数据
    • 当缓冲池不为空时,消费者才能读取数据

    1.2 解决方法

    设置3个信号量:mutex=1,full=0,empty=n(假设缓冲池大小为n)

    • mutex:互斥信号量
    • full:表达缓冲池中数据量的信号量,初值为0
    • empty:表达缓冲池中空闲块的信号量,初值为n,即缓冲池的大小
    • 生产者
    P(empty)
    P(mutex)
    写入数据
    V(mutex)
    V(full)
    
    • 消费者
    P(full)
    P(mutex)
    读取数据
    V(mutex)
    V(empty)
    

    二、读者与写者问题

    2.1 问题概述

    一个数据对象(如文件、记录)可以被多个进程共享。这些进程可以分为两类:

    • 读者进程:只读取数据对象的值
    • 写者进程:修改或者写入数据对象的值

    这类问题具有以下特点:

    1. 读者进程之间不互斥
    2. 写者与写者、写者与读者之间互斥

    2.2 解决方法

    设置3个信号量:mutex,readerCount,writer

    • mutex:互斥信号量,用于读者进程访问共享变量readerCount,初值为1
    • readerCount:共享信号量,用于记录当前进入临界区的读者进程的数量,初值为0
    • writer:互斥信号量,用于写者与写者、写者与读者之间对临界区的互斥访问
    • 读者
    P(mutex)
    //临界区没有读者时,先判断当前临界区是否有写者进程
    //由第一个进入临界区的读者进程来阻塞后来的写者进程
    if(readerCount == 0)
        P(writer);
    //当此时临界区已经存在读者进程时,countReader++
    ++readerCount;
    V(mutex)
    读数据
    P(mutex)
    --readerCount;
    //由最后一个离开临界区的读者进程唤醒可能被阻塞的写者进程
    if(readerCount == 0)
        V(writer);
    V(mutex)
    
    • 写者
    P(writer)
    写数据
    V(writer)
    

    三、哲学家进餐过程

    3.1 问题概述

    五个哲学家,他们的生活方式是交替地进行思考和进餐。哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子。

    • 平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,
    • 进餐完毕,放下筷子又继续思考。

    3.2 解决方法

    对于上述问题,很容易想到这样一种方法:设置一个互斥信号量数组,第i个哲学家进餐时,分别P(mutex[i-1])和P(mutex[i])。

    while(1){
    P(mutex[i])
    P(mutex[(i+1)%5])
    进餐
    v(mutex[i])
    V(mutex[(i+1)%5])
    思考}
    

    但是上述方法很容易引起死锁。为了解决死锁问题,可以考虑以下方法:

    • 至多允许四个哲学家同时进餐。
    • 仅当左、右两支筷子均可用时,才允许拿起筷子进餐。
    • 奇数号哲学家先拿左筷子再拿右筷子,偶数号哲学家相反。
    展开全文
  • 操作系统——进程同步与互斥

    千次阅读 2019-10-21 22:13:19
    文章目录进程同步与互斥简介进程间合作进程间合作的问题竞争条件原子操作临界区相关的几个概念忙等待的互斥基于硬件的同步解决办法:屏蔽中断基于软件的同步解决方法严格轮换法Peterson解法N线程的软件方法基于软件...
  • 大连理工大学操作系统大作业, 进程同步与互斥 生产者与消费者问题
  • Java实现的进程同步与互斥(PV) Hao语言

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,363
精华内容 1,345
关键字:

进程同步与互斥