# TrieadOwner reference

The TrieadOwner is defined in

    app/TrieadOwner.h

. Its constructor is protected, the normal way of constructing is by calling

    App::makeTriead()

. This is also called defining a Triead.

TrieadOwner is an Starget, and must be accessed only from the thread that owns it (though it's possible to create it in the parent thread and then pass to the actual owner thread, as long as the synchronization between the threads is done properly).

    Triead *get() const;

Get the public side if the Triead. In &Cpp;, unlike Perl, the Triead methods are not duplicated in TrieadOwner. So they are accessed through

    get()

, and for example to get the Triead name, call

    to->get()->getName()

. The TrieadOwner holds a reference to Triead, so the Triead object will never get destroyed as long as the TrieadOwner is alive.

    App *app() const;

Get the App where this Triead belongs. The TrieadOwner holds a reference to App, so the App object will never get destroyed as long as the TrieadOwner is alive.

    bool isRqDead() const;

Check whether this triead has been requested to die.

    void requestMyselfDead();

Request this thread itself to die (see the extended description in the Perl reference).

    Unit *unit() const;

Get the main unit of this Triead. It has the same name as the Triead itself.

    void addUnit(Autoref u);

Keep track of an additional unit. Adding a unit multiple times has no effect. See the other implications in the Perl reference.

    bool forgetUnit(Unit *u);

Forget about an additional unit. If the unit is already unknown, has no effect. The main unit can not be forgotten.

    typedef list > UnitList;
    const UnitList &listUnits() const;

List the tracked units. The main unit is always included at the front of the list.

    void markConstructed();

Advance the Triead state to Constructed. Repeated calls have no effect.

    void markReady();

Advance the Triead state to Ready. Repeated calls have no effect. The advancement is cumulative: if the Triead was not constructed yet, it will be automatically advanced first to Constructed and then to Ready. If this is the last Triead to become ready, it will trigger the App topology check, and if the check fails, abort the App and throw an Exception.

    void readyReady();

Advance the Triead to the Ready state, and wait for all the Trieads to become ready. The topology check applies in the same way as in

    markReady()

.

    void markDead();

Advance the Triead to the Dead state. If this Triead was not Ready yet and it's the last one to become so, the topology check will run. If the topology check fails, the App will be aborted but

    markDead()

will not throw an exception.

This method is automatically called from the TrieadOwner destructor, so most of the time there is no need to call it explicitly.

It also clears all the tracked units.

    void abort(const string &msg) const;

Abort the App. The name of this thread will be forwarded to the App along with the error message. The error message may be multi-line.

    Onceref findTriead(const string &tname, bool immed = false);

Find a Triead in the App by name. The flag

    immed

controls whether this method may wait. If

    immed

is false, and the target thread is not constructed yet (but at least declared), the method will sleep until it becomes constructed, and then returns it. If the target thread is not declared, it will throw an Exception. If

    immed

is true, the look-up is immediate: it will return the thread even if it's not constructed but is at least defined. If it's not defined (even if it's declared), an Exception will be thrown. The look-up of this Triead itself is always immediate, irrespective of the

    immed

flag, to avoid deadlocking itself.

An Exception may also be thrown if a circular sequence of Trieads deadlocks waiting for each other.

    Onceref exportNexus(Autoref facet, bool import = true);

Export a Nexus. The Nexus definition is constructed as a Facet object, which is then used by this method to construct and export the Nexus. The same argument Facet reference is then returned back as the result. The

    import

flag tells, whether the Nexus is to be also imported back by connecting the same original Facet object to it. If import is false, the original Facet reference is still returned back but it can't be used for anything, and can only be thrown away. The direction of the import (reading or writing) is defined in the Facet, as well as the nexus name and all the other information.

Throws an Exception on any errors, in particular on the duplicate facet names within the Triead.

    Onceref exportNexusNoImport(Autoref facet);

A convenience wrapper around exportNexus() with

    import=false

.

    Onceref importNexus(const string &tname,
    	const string &nexname, const string &asname,
    	bool writer, bool immed = false);

Import a Nexus from another Triead.

    tname

is the name of the other thread,

    nexname

is the name of nexus exported from it,

    asname

is the local name for the imported facet ( means same as

    nexname

), the

    writer

flag determines if the import is for writing, and the

    immed

flag has the same meaning as in

    findTriead()

. The import of a nexus involves finding its exporting thread, and the

    immed

flag controls, how this finding is done.

Throws an Exception if anything is not found, or the local import name conflicts with another imported facet.

    Onceref importNexusImmed(const string &tname,
    	const string &nexname, const string &asname, bool writer);
    Onceref importReader(const string &tname,
    	const string &nexname, const string &asname = "", bool immed=false);
    Onceref importWriter(const string &tname,
    	const string &nexname, const string &asname = "", bool immed=false);
    Onceref importReaderImmed(const string &tname,
    	const string &nexname, const string &asname = "");
    Onceref importWriterImmed(const string &tname,
    	const string &nexname, const string &asname = "");

Convenience wrappers for

    importNexus()

, providing the default arguments and the more mnemonic names.

    typedef map > NexusMap;
    void exports(NexusMap &ret) const;

Get the nexuses exported here. The map argument will be cleared and refilled with the new values.

    typedef map > FacetMap;
    void imports(FacetMap &ret) const;

Get the facets imported here. The map argument will be cleared and refilled with the new values.

    NexusMaker *makeNexusReader(const string &name);
    NexusMaker *makeNexusWriter(const string &name);
    NexusMaker *makeNexusNoImport(const string &name);

A convenient way to build the nexuses for export in a chained fashion. The name argument is the nexus name. The NexusMaker is an opaque class that has the same building methods as a Facet, plus the method

    complete()

that finishes the export. This call sequence is more convenient than building a Facet and then exporting it. For example:

    Autoref myfacet = ow->makeNexusReader("my")
    	->addLabel("one", rt1)
    	->addFromLabel("two", lb2)
    	->setContext(new MyFnContext)
    	->setReverse()
    	->complete();

Only one nexus may be built like this at a time, since there is only one instance of NexusMaker per TrieadOwner that gets reused over and over. It keeps the Facet instance being built in it. If you don't complete the build, that Facet instance will be left sitting around until another

    makeNexus*()

call, when it will get thrown away. But in general if you do the calling in the sequence as shown, you can't forget to call

    complete()

at the end, since otherwise the return type would not match and the compiler will fail.

    bool flushWriters();

Flush all the writer facets. Returns true on the successfull completion, false if the thread was requested to die, and thus all the output was thrown away.

    bool nextXtray(bool wait = true, const struct timespec *abstime =
    	(const struct timespec *)NULL);

Read and process the next Xtray. Automatically calls the

    flushWriters()

after processing. The rest works in the same way as described in Perl, however this is a combination of Perl's

    nextXtray()

,

    nextXtrayNoWait()

and

    nextXtrayTimeLimit()

in one method. If

    wait

is false, this method will never wait. If

    wait

is true and the

    abstime

is not NULL, it might wait but not past that absolute time. Otherwise it will wait until the data becomes available or the thread is requested to die.

Returns true if an Xtray has been processed, false if it wasn't (for any reason, a timeout expiring or thread being requested to die).

    bool nextXtrayNoWait();

A convenience wrapper over

    nextXtray(false)

.

    bool nextXtrayTimeout(int64_t sec, int32_t nsec);

Another convenience wrapper over

    nextXtray()

: read and process an Xtray, with a timeout limit. The timeout value consists of the seconds and nanoseconds parts.

    void mainLoop();

Run the main loop, calling

    nextXtray()

repeatedly until the thread is requested to die.

    bool isRqDrain();

Check if a drain is currently requested by any thread (and applies to this thread). In case if an exclusive drain is requested with the exclusion of this thread, this method will return false.

    void requestDrainShared();
    void requestDrainExclusive();
    void waitDrain();
    bool isDrained();
    void drainShared();
    void drainExclusive();
    void undrain();

The drain control, same as in Perl. These methods are really wrappers over the corresponding App methods. And generally a better idea is to do the scoped drains with AutoDrain rather than to call these methods directly.

The &Cpp; API provides no methods for the file descriptor tracking as such. Instead these methods are implemented in the class FileInterrupt. TrieadOwner has a public field

    Autoref fileInterrupt_;

to keep an instance of the interruptor. TrieadOwner itself has no use for it, nor does any other part of Triceps, it's just a location to keep this reference for the convenience of the application developer. The Perl API makes use of this location.

But how does the thread then get interrupted when it's requested to die? The answer is that the TrieadJoin object also has a reference to the FileInterrupt object, and even creates that object in its own constructor. So when a joiner method is defined for a thread, that supplies the App with the access to its interruptor as well. And to put the file descriptors into the FileInterrupt object, you can either keep a direct reference to it somewhere in your code, or copy that reference into the TrieadOwner object.

Here is for example how the Perl thread joiner is created for the TrieadOwner inside the Perl implementation:

    string tn(tname);
    Autoref to = appv->makeTriead(tn, fragname);
    PerlTrieadJoin *tj = new PerlTrieadJoin(appv->getName(), tname,
    	SvIOK(tid)? SvIV(tid): -1,
    	SvIOK(handle)? SvIV(handle): 0,
    	testfail);
    to->fileInterrupt_ = tj->fileInterrupt();
    appv->defineJoin(tn, tj);

This is somewhat cumbersome, but the native &Cpp; programs can create their threads using the class BasicPthread that takes care of this and more.

TrieadOwner
FileInterrupt
TrieadJoin