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

    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.进程通信
            领会
                共享内存
                    在相互通信的进程之间设有一个公共内存区,一组进程向该公共内存中写,另一组进程从公共区中读
                消息队列
                    进程间的数据交换,是以格式化的消息为单位的。程序员直接利用操作系统提供的一组通信命令,实现大量数据的传递,通信过程对用户是透明的
                信箱机制
                    以发送信件以及接受回答信件为进程间通信的基本方式
                管道
                    连接两个进程之间的一个打开的共享文件,专用于进程之间进行数据通信。发送进程可以源源不断地从管道一端写入数据流,接收进程在需要时可以从管道的另一端读出数据,写入和读出的信息长度都是可变的

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

    万次阅读 2018-06-18 08:13:41
    经典进程同步与互斥问题 1. 生产者-消费者问题 1.1 简单的“生产者-消费者”问题 设进程A、B是两个相互合作的进程,它们共享一个缓冲区,进程A向其中写入数据,进程B从中读出数据。producer:生产者进程,...

    经典进程同步与互斥问题

    1. 生产者-消费者问题

    1.1 简单的“生产者-消费者”问题

    设进程A、B是两个相互合作的进程,它们共享一个缓冲区,进程A向其中写入数据,进程B从中读出数据。producer:生产者进程,consumer:消费者进程。当缓冲区不空时,消费者便可以读数据;当缓冲区为空时,生产者便可以写数据。
    生产者消费者模型

    设置信号量:
    full:表示有数据缓冲区的数目,初值为0;
    empty:表示空缓冲区的数目,初值为1;

    生产者:

    do  {
        //   produce an item
        wait (empty);
        //  add the item to the  buffer
        signal (full);
    } while (TRUE);
    

    消费者:

    do {
        wait (full);    
        //  remove an item from  buffer
        signal (empty);
        //  consume the item
    } while (TRUE);
    
    1.2 复杂的““生产者-消费者”问题”

    复杂的生产者消费者模型
    特点:
    1. 若干进程通过有限的共享缓冲池交换数据。
    2. 一组“生产者”进程不断写入,而一组“消费者”进程不断读出;
    3. 任何时刻只能有一个进程可对共享缓冲池进行操作

    分析:
    1. 消费者取数据时,缓冲池至少有一个有数据的缓冲区
    2. 生产者发送数据时,缓冲池至少有一个空缓冲区
    3. 缓冲池是临界资源,各个生产者和消费者之间必须互斥访问

    设置信号量:
    empty :表示空缓冲区个数,初值为n;
    full :表示有数据的缓冲区个数,初值为0;
    mutex :用来控制互斥的访问缓冲区,初值为1;

    生产者:

    do  {      
        //   produce an item
        wait (empty);   
        wait(mutex);
        //  add the item to the  buffer
        signal(mutex);
        signal (full);
    } while (TRUE);
    

    消费者:

    do {
            wait (full);
            wait(mutex);
            //  remove an item from  buffer
            signal(mutex); 
            signal (empty);
           //  consume the item
    } while (TRUE);
    

    在生产者—消费者问题中,不能将生产者进程的wait(empty)和wait(mutex)语句互换。因为生产者若是先拿到了mutex锁,然后发现没有空缓冲区,那么就会一直等待,同时一直拿着mutex锁。要注意到,mutex锁是生产者和消费者共享的,此时生产者拿着锁一直等待消费者消费,而消费者一直拿不到mutex锁,则会造成死锁。

    2. 读者-写者问题

    一些进程只读数据,称“读者”;另一些会对数据进行修改,称“写者”。写者与写者互斥,写者与读者互斥;读者之间不互斥。

    对于写进程而言:
    1. 一定是互斥访问。要保证写者和读者互斥,以及写者和写者互斥。

    对于读进程而言:
    1. 如果是第1个读者,要实现与写者的互斥;如果是后继读者,则不需要。
    2. 如果是最后一个读者,需要考虑唤醒阻塞的写者,以便能够让写者有机会进入临界区。

    设置信号量:
    wmutex :控制写者互斥的访问共享数据,初值为1;
    readcount :读者计数器,记录当前读者数,初值为0;
    rmutex :控制读者互斥访问readcount,初值为1;

    二者流程图如下:
    写者

    读者

    写进程:

    do {
        wait (wmutex) ;
        //    writing is performed
        signal (wmutex) ;
    } while (TRUE);

    读进程:

    do {
        wait (rmutex) ;
        readcount ++ ;
        if (readcount == 1)  
        wait (wmutex) ;
        signal (rmutex)
    
        // reading is performed     //注意这里特意空出来的原因
    
        wait (rmutex) ;
        readcount  - - ;
        if (readcount  == 0)  
        signal (wmutex) ;
        signal (rmutex) ;
    } while (TRUE);
    

    在读进程读的过程中,只需保证在对读者数量变化时是互斥即可。

    3. 哲学家进餐问题

    假设5个哲学家围绕一张圆桌而坐,桌上放着5根筷子,哲学家进餐时需要同时拿起他左边和右边的两根筷子。
    哲学家进餐问题模型

    思路一:
    1. 对于每一个哲学家,先等待左边的筷子可用,然后等待右边的筷子可用
    2. 吃饭
    3. 放下两根筷子

    do  { 
        wait ( chopstick[i] );
        wait ( chopStick[ (i + 1) % 5] );
        //  eat
        signal ( chopstick[i] );
        signal (chopstick[ (i + 1) % 5] );
        //  think
    } while (TRUE);

    这样势必会导致一个问题:在极端情况下,5个哲学家同时拿起左边的筷子,那么势必会造成每个人都只有左筷子而没有右筷子,每个人都在等待右筷子。造成死锁现象。

    解决死锁问题的方法:
    方法一:同时最多允许四个哲学家围坐在桌子周围。
    方法二:只有在哲学家两侧的筷子都可用时才允许她捡起筷子。

    思路二:
    对于每一个哲学家,要求同时拿起两根筷子,要么一根都不拿。

    do  { 
        Swait ( chopStick[ (i + 1) % 5], chopstick[i] );
        //  eat
        Ssignal (chopstick[ (i + 1) % 5], chopstick[i] );
        //  think
    } while (TRUE);
    展开全文
  • 操作系统——进程同步与互斥

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

空空如也

空空如也

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

进程同步与互斥