← Back to team overview

opencog-dev team mailing list archive

Fwd: Threaded agents and attention allocation

 

---------- Forwarded message ----------
From: Joel Pitt <joel.pitt@xxxxxxxxx>
Date: Thu, Jul 10, 2008 at 12:01 PM
Subject: Threaded agents and attention allocation
To: Gustavo Machado Campagnani Gama <gama@xxxxxxxxxxxxx>


Hi Gama,

On Tue, Jul 8, 2008 at 9:57 AM, Gustavo Machado Campagnani Gama
<gama@xxxxxxxxxxxxx> wrote:
> Hi Joel/David,

> On Wed, 2008-07-02 at 16:25 +1200, Joel Pitt wrote:
>> The AtomSpace and AtomTable test examples seem to lock the entire
>> table. Do I need to do the same thing while processing the
>> neighbouring atoms, or is there a finer level of locking available
>> somehow?
>
> Unfortunately no. The only way we may assure that no atoms will be
> removed while we're building the list of HandleEntrys is by locking the
> AtomTable. However, once the list is built, only the atoms in it need to
> be locked; the table itself may be released.

Ah okay, I think I understand now.

> Ideally, you'd use the lockable container to handle the "atom locks". To
> illustrate it, I've hastily cooked up the attached patch implementing a
> "getLockedNeighbors" method (I haven't tested it though, so use with
> care). Assuming the patch works, what you should do is replace the
> getNeighbors calls on your code and replace with corresponding
> getLockableNeighbors calls. But, as noted on the README, be careful with
> the lifecycle of the container you pass to the getLockableNeighbors
> method: the atoms will be locked until the container is destroyed.

Thanks! Turns out I didn't need the getNeighbours function in the new
code I was writing, but I'll have to update some earlier stuff. Will
be sure to test it though.

> My original idea was to use a very simple start/stop interface for the
> Agents. The Server would provide load/unload operations (similar to the
> current dlopen and dlclose). Internally, the server would also provide a
> method getAgent(std::string name) (or getAgent(int id)) so that agents
> could communicate with each other. And I was considering converting the
> current command processor to use agents -- but I'm not unsure about the
> performance implications of starting a new thread for each command.

Sounds reasonable to me, but yeah, I'm not familiar enough with
threading to comment about performance if threads are started for each
new command.

> That's about it; everything else would be up to the agents:
>   - if an agent should use all the available CPU, then it just never
>     sleeps; the kernel will preempt it as it does any other thread
>     (the agent should probably lower its priority though).
>   - if another agent should run every X cycles, then it simply issues
>     a "sleep" call at the end of its main loop.
>   - if an agent wants to start another agent, it calls the
>     "server().startAgent()" method
>   - if an agent needs to send a message to another agent, it retrieves
>     the instance thorugh "server().getAgent()", casts the Agent
>     reference to the proper Agent class and calls the desired method.

I'll have to change the attention allocation system to be compatible,
although I have to do change it anyhow...

After discussion with Ben, we decided that conversion from stimulus
(the quantity that MindAgents reward useful atoms with) should be
converted to short term importance (STI) after each MindAgent runs.
This is because the amount of STI to reward per unit of stimulus is
dependent on the amount of STI the MindAgent has to distribute. This
prevents a MindAgent that isn't particular effective (in achieving
system goals) from upping the importance of the atoms it uses - since
they are not important in the overall OpenCog instance.

At the moment, stimulus -> STI/LTI is just done by the
ImportanceUpdatingAgent (along with collecting rent and taxation when
necessary). For the above stim->STI/LTI scheme, it'd probably be
better to include it as a separate process.

I'm thinking:
  * move the atom stimulus map from the AtomSpace to a separate map
per MindAgent.
  * In the MindAgent class, provide a method rewardAtoms() which
calls the WageAgent. This method would also signal to the WageAgent
who the caller was so that the correct stimulus map and amount of STI
for reward could be worked out.
  * It's up to the MindAgent to figure out the appropriate time to
reward the atoms it uses. Usually at the end of a run cycle.

Comments welcome :)

> Nothing is set in stone, of course, and I'd be glad to hear about any
> other important requirements. Keep in mind though that nothing prevents
> us from refining the proposed design and add additional functionality in
> the future. What I'm mostly concerned right now is to have something
> that's simple (and extensible) so that we may have it up and running
> relativelly soon.

One requirement I'm thinking about is trying to obtain a lock on the
AtomTable. Does the thread system we use queue these attempts, or are
they poll based? (perhaps all thread implementations are one or the
other, apologies for my ignorance). Ideally they'd be queue based,
since certain agents (like the Rent collection agent that will be
split off of the ImportanceUpdating agent) need a lock on the entire
table - and for sensible behavior they should occur at reasonably
regular intervals.

Another question with the locking. What happens when:

1. Agent one has an lvector containing atoms [A, B]
1. Agent two has an lvector containing atoms [C, D]

Agent one requests a lock on atom C, so it waits for Agent two to
release it. But then Agent two requests a lock on atom A. Would this
be a race condition? Or is this situation avoided by having the
AtomTable lock?

Not trying to nitpick, just trying to understand how things work so my
code is thread safe!

Thanks,

J



Follow ups