digraph TwoPhaseProtocol {
    // General Graph Settings
    graph [rankdir=TB, fontname="Helvetica,Arial,sans-serif"];
    node [fontname="Helvetica,Arial,sans-serif", shape=rect];
    edge [fontname="Helvetica,Arial,sans-serif"];

    subgraph cluster_waiter {
      label = "Waiting Thread (Consumer)";
      style = dashed;
      color = "#aaaaaa";
    // Nodes
    Start [shape=record, label=" A worker thread (wid)\nwanting to wait ", fillcolor=black];
    End [label=" waiter queue ", style=filled, fillcolor=black, fontcolor=white];

    Check1 [shape=diamond, label=" Predicate\nTrue? "];
    Act1   [label=" act() "];

        Prepare [label=" Phase 1: prepare_wait(wid) "];
        Check2  [shape=diamond, label=" Predicate\nTrue? "];
        Cancel  [label=" cancel_wait(wid) "];
        Act2    [label=" act() "];
        Commit  [label=" Phase 2: commit_wait(wid) "];


    // Logic Flow
    Start   -> Check1;
    Check1  -> Act1    [label=" Yes "];
    Check1  -> Prepare [label=" No "];
    
    Prepare -> Check2;
    Check2  -> Cancel  [label=" Yes"];
    Cancel  -> Act2;
    Check2  -> Commit  [label=" No "];

    // Exit points
    Act1   -> Start;
    Act2   -> Start;
    Commit -> End;
    }
    
    subgraph cluster_notifier {
      label = "Notifier Thread (Producer)";
      style = dashed;
      color = "#aaaaaa";
      Notifier [label=" A worker thread (wid)\nwanting to notify "]
      ModifyPredicate [label="Predicate = True"]
      Notify [label=" notify_one(wid)\nor\nnotify_all(wid)"]
      
      Notifier -> ModifyPredicate;
      ModifyPredicate->Notify;
    }
}
