亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

與信號量同步的“階段”序列無法正常工作

與信號量同步的“階段”序列無法正常工作

開心每一天1111 2023-03-17 15:23:47
我正在學習線程和同步,我正在嘗試建立一個“階段”系統,其中第一階段生成一條消息(為方便起見,一個 int),然后將其傳遞給第二階段,第二階段修改它(乘以2),然后將其傳遞到最后一個階段,該階段進一步修改它并將其打印到控制臺。問題是第三階段永遠不會運行,即使它收到了消息。在我的示例中,我設置了一個名為“資源”的信號量數組,其中信號量 A(索引 0)有 4 個許可,信號量 B 有 3 個,C 有 2 個。所有設置都是公平的。我嘗試將信號量設置為公平,但這并沒有解決我的問題。我也試過改變睡眠時間,但沒有成功。class Fase1 extends Thread{    private int i = 0;    private Semaphore[] resources;    private Fase2 recipient;    public Fase1(Semaphore[] res, Fase2 fase2){        recipient=fase2;        resources=res;    }    @Override    public void run(){        try{            while(true){                resources[0].acquire(2);                resources[1].acquire(2);                recipient.receiveMessage(i);                i++;                sleep(200);                resources[1].release(2);                resources[0].release(2);            }        } catch (InterruptedException e){        }    }}class Fase2 extends Thread{    private Semaphore[] resources;    private Fase3 recipient;    private boolean receivedMessage = false;    private int message = 0;    public Fase2(Semaphore[] res, Fase3 fase3){        recipient=fase3;        resources=res;    }    @Override    public void run(){        try{            while(true){                if(receivedMessage){                    resources[0].acquire(2);                    resources[1].acquire(2);                    resources[2].acquire(2);                    recipient.receiveMessage(message*2);                    receivedMessage = false;                    sleep(200);                    resources[2].release(2);                    resources[1].release(2);                    resources[0].release(2);                }            }        } catch (InterruptedException e){        }    }    public void receiveMessage(int msg){        message = msg;        receivedMessage = true;    }}我注意到許可證不知何故被搞砸了,幾乎就像一些線程沒有正確釋放它們一樣,即使這對我來說似乎是正確的。
查看完整描述

1 回答

?
神不在的星期二

TA貢獻1963條經驗 獲得超6個贊

您的設計存在一個根本缺陷:您正在同步對message資源的訪問,而不是對receivedMessage標志的訪問。當您在線程 #2 中設置標志時true,JVM 沒有義務將該寫入傳播到線程 #3,因為該線程在進入塊內之前不會執行同步if,而這很可能永遠不會發生。這同樣適用于線程#1 和#2 之間的通信。

and操作充當同步點,并且將使寫入在線程間可見,因此您需要在檢查標志之前調用它們acquire()。例如在:release()Fase3

  @Override

    public void run(){

        try{

            while(true){

                resources[1].acquire(2); // All writes by thread #2 are now visible

                if(receivedMessage){

                    resources[2].acquire(2);

                    System.out.println(message+1);

                    sleep(200);

                    receivedMessage = false;

                    resources[2].release(2);

                }

                resources[1].release(2);

            }

        } catch (InterruptedException e){

        }

    }

還有另一種解決方案,即制作receivedMessageflags volatile,但正確使用單個鎖定機制更清晰。

作為旁注,最好使用Runnables 而不是 extendingThread。



查看完整回答
反對 回復 2023-03-17
  • 1 回答
  • 0 關注
  • 108 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號