Data Driven Programming Change Nets Dr. Werner Van Belle e-mail:...

Post on 03-Jan-2016

215 views 0 download

Tags:

Transcript of Data Driven Programming Change Nets Dr. Werner Van Belle e-mail:...

Data Driven ProgrammingChange Nets

Dr. Werner Van Bellee-mail: werner.van.belle@bio6.itek.norut.noe-mail: werner@onlinux.bePhone: +47 776 29 40411 November 2005

1. Connections

Connections Multiple 'actors' that can be

separated in time

separated in space

Communicate through connections shared data

self contained (messages)

Different implementation flavors processes, threads, thunks, longjumps, callbacks,...

copy-on-write, fetch-on-access, serialization

Connection Based Programming Provides

loose coupling: every actor can connect any two different actors

actors do not need to know to whom they will be connected

dissociation of control flow and code: send and forget

suitable for distributed systems

efficient local execution (10x slower than function calls)

increased flexibility: rerouting of connections, multiple receivers

Program Layout Programming larger applications consists of

combining methods and functions to bring a program from one state to another

to be modular, often a mixture of action calls ('print out this file') state reactions ('queue contains file to print')

Focus here on state 'reactive' programming a natural use of connections

2. Updates

Updating strategy

1.Change the variable or data content

2.Send out a change notification

3.Listeners receive update and 'react' to the new state

Advantage Efficient for both message based and thread based

connection models.

Disadvantage update loops

Scenario Queue

push(string)

pop()

PrintingQueue relies on a 'waiting' queue for data storage

pops, prints, stops, pops, prints, stops, ...

How to functionally connect these two objects ?How to functionally connect these two objects ?

Scenario Connect a Queue state change to the

PrintingQueue void Queue::push(string s) { files.push_back(s); updated(); }

void PrintingQueue::state_changed(){ if (printing) return; string s = waiting->pop(); printing=true;}

Update Loop atwaiting->pop() !

Update Loop atwaiting->pop() !

direct connection (call / callback)

string Queue::pop() { string s = files.pop_front(); updated();

return s; }

Scenario

void Queue::push(string s) { files.push_back(s); updated(); }

void PrintingQueue::state_changed(){ if (printing) return; string s = waiting->pop(); printing=true;}

indirect connection (Threaded Asgeir style)

All interested partners want to be notified at least once !

All interested partners want to be notified at least once !

Changedpush

poppop

Scenario

void Queue::push(string s) { files.push_back(s); updated(); }

void PrintingQueue::state_changed(){ if (printing) return; string s = waiting->pop(); printing=true;}

indirect connection (message-queue / receiver)

Needless changed messages !Needless changed messages !

Changedpushpop

pop

Changed

pushChanged

Scenario

void Queue::push(string s) { files.push_back(s); updated(); }

void PrintingQueue::state_changed(){ if (printing) return; string s = waiting->pop(); printing=true;}

indirect connection (eventObjects)

Queue state will be accessedconcurrently, popping of change shouldlock queue, deadlocks/livelocks in manyscenarios

Queue state will be accessedconcurrently, popping of change shouldlock queue, deadlocks/livelocks in manyscenarios

pushpop

pop

Changed

pushChanged

Changed

poppush

Update Loops Direct loops avoided using distinct names

poppop_without_update

pop_updatepush_update

pop_from_printer_queuepop_from_other_actor

Leads to unclear naming convention & usage dependency

indirect conflicts with extra actors (log connected to queue)

multi hop loops tend to be difficult to avoid

Update Loops Other solutions include

loop breaking using version numbers

loop breaking using locking

loop breaking points using comparison checks

All of these can work but they tend to be scattered throughout the code !

Control flow of the overall program is difficult to understand

3. Formal State Transition

Petri-Nets Tokens: a piece of data, a message

Petri-Nets Places: contain zero, one or more tokens

Petri-Nets Transitions: can move tokens between places

can fire when all inputs provide a suitable token (pre-condition / guarding)

when fired, removes all input tokens and creates new output tokens (post-condition)

fire atomically (no concurrent transitions)

The Printing Queue Petri-Net

Petri-Nets

Petri-Nets

Petri-Nets Advantages

Good program documentation

Possibility to simulate message flow, without working program

Formal proof of boundedness, reachability (homestate), deadlock-freedom

Efficient implementation through locality-principle

Can we use Petri-nets as a change notification mechanism ?Can we use Petri-nets as a change notification mechanism ?

Tracking Change with Petri-Nets

Petri-Nets Disadvantages

Formal guard requirements are too broad to implement efficiently (search for a matching binding problem).

Programming with Petri-nets difficult because tokens are consumed. All state is volatile.

Petri-nets are good for constraint checkingThey fail to provide natural change tracking capabilities

Petri-nets are good for constraint checkingThey fail to provide natural change tracking capabilities

Change Nets Modification to Petri-nets

There is always exactly one token per place.

Transition are extended with 'might-be-enabled' flag.

'might-be-enabled' is updated whenever any of the input places changes state

Once 'might-be-enabled', the constraint associated with the transition can be checked

Then the transition can be fired

1. Change messages are separated in time -> no direct loop updates2. Change messages are only send if change occurs -> no indirect loops3. Multiple changes result in one change message per listener4. Change messages do no contain the data -> lightweight

1. Change messages are separated in time -> no direct loop updates2. Change messages are only send if change occurs -> no indirect loops3. Multiple changes result in one change message per listener4. Change messages do no contain the data -> lightweight

No update Loops

var<int> a(0); var<int> b(0); var<int> c(0);

a.update_to(b); b.update_to(c); c.update_to(a);

a=10;

Content FireableA B C A-B B-C C-A0 0 0 0 0 0

a=10 10 0 0 1 0 0execute b = a 10 10 0 0 1 0execute c = a 10 10 10 0 0 1execute a = c 10 10 10 0 0 0

Queue

class Queue: public Place{ list<string> files; void push(string s) { files.push_back(s); updated(); } string pop() { string s = files.front(); files.pop_front(); updated(); return s; }};

PrintingQueue

class PrintingQueue{ Queue * waiting; var<bool> printing; PrintingQueue(Queue *q); void state_changed();};

PrintingQueue::PrintingQueue(Queue *q) : waiting(q){new MemberTransition<PrintingQueue>(*this, &PrintingQueue::state) ->react_on(waiting); ->react_on(printing);printing = false;}

PrintingQueue

void PrintingQueue::state_changed(){ if (printing) return; string s = waiting->pop(); printing=true;}

Queue * q = new Queue(); PrintingQueue pq1(q); PrintingQueue pq2(q); q->push("File1"); q->push("File2");

Multi-Threaded Change Nets

1.Transition waits for a changed state

2.Clear state

3.Sorted waiting acquisition of input locks & output locks

4.Checks constraints

5.Execute transition

6.Releases locks

Intermediate Conclusion Petri-nets are a natural way to think about state

changes in programs

Change nets well defined based on Petri-nets (can be automatically generated in function of the constraint net)

Change net transitions provide a clear, transparent way to glue programs together

Change nets can be efficiently implemented in process, thread & thunk based execution models.

4. Implementation

Places

class Place{ // all the listeners to state changes on this place vector<Transition*> output_transitions; public: void update_to(Transition*t) {output_transitions.push_back(t);}; // will update all the output transitions 'changed' state void updated();};

void Place::updated(){ for(int i = 0 ; i < output_transitions.size() ; i++) output_transitions[i].input_place_changed=true;}

Transitions

class Transition{ bool input_place_changed; // might_be_enabled // will create a transition and add it to the global net Transition(); // will mark this transition as 'possible' executable void set_input_place_changed() { input_place_changed=true; }; // will inform this transition to react on changes at place void react_on(Place*p) {p->update_to(this);}; // will check the might_be_enabled state and run if necessary void execute(); virtual void run() = 0;};

void Transition::execute(){ if (!input_place_changed) return; input_place_changed = false; run();}

Convenience Classes - Variables

template <class T> class var: public Place{ T value; public: var<T>() : Place() {}; var<T>(T init) : Place(), value(init) {}; void update_to(var<T> & other); operator const T&(void) {return value;}; operator const T&(void) const {return value;}; var<T>& operator= (const var<T>& f); var<T>& operator= (const T& f);};

Convenience Classes - Variables

template <class T> var<T>& var<T>::operator= (const var<T>& f){

if (value==f.value) return *this;value=f;updated();return * this;

}

Convenience Classes – Member Transitions

template <class H> class MemberTransition: public Transition{ public: typedef void (H::*member)(); member F; H& o; MemberTransition(H &ob, member i) : o(ob) {F=i;}; virtual void run() {((o).*(F))();};};

Conclusion Petri-nets are a natural way to think about state

changes in programs

Change nets well defined based on Petri-nets (can be automatically generated in function of the constraint net)

Change net transitions provide a clear, transparent way to glue programs together

Change nets can be efficiently implemented in process, thread & thunk based execution models.

5. Extra: Trolltech Connections

Connections - Trolltech Multi-threaded

Signals – emit function calls

Slots – accepts function calls

On an i586-500, you can emit around 2,000,000 signals per second connected to one receiver, or around 1,200,000 per second connected to two receivers. The simplicity and flexibility of the signals and slots mechanism is well worth the overhead, which your users won't even notice.

Connections - Trolltech

Connections - Trolltech

#include <QObject>

class Counter : public QObject { Q_OBJECT int m_value; public: Counter() { m_value = 0; } int value() const { return m_value; } public slots: void setValue(int value); signals: void valueChanged(int newValue); };

Connections - Trolltech

void Counter::setValue(int value) { if (value != m_value) { m_value = value; emit valueChanged(value); } }

Connections - Trolltech

class LcdNumber : public QFrame{ Q_OBJECT public: LcdNumber(QWidget *parent = 0); public slots: void display(int num); void display(double num); void display(const QString &str); void setHexMode(); void setDecMode(); void setOctMode(); void setBinMode(); void setSmallDecimalPoint(bool point);};

Connections - Trolltech

Counter * a = new Counter();LcdNumber * l = new LcdNumber();

connect(a,SIGNAL(valueChanged(int)), l,SLOT(display(int)))