Update:

After some heavy lifting I have more or less isolated the resultant crash to always occur here:

taskletobject.c
--------------

void
slp_current_insert(PyTaskletObject *task)
{
    PyThreadState *ts = task->cstate->tstate;
    PyTaskletObject **chain = &ts->st.current;

    SLP_CHAIN_INSERT(PyTaskletObject, chain, task, next, prev);
    ++ts->st.runcount;
}


due to 'task' being in a bad (but not generic memory corrupted, at least it doesn't look like it) state. task->cstate is null, as are next/prev.. refcnt is 4 and recursion depth is 1.. yeah few more crashes it always looks about that way.

BUT if I amend worker to look like this:

worker()
{
// blah blah wait on queue and get a job and do some work waiting for awhile (or returning immediately)

EnterCriticalSection( &stacklessLock ); // do not risk access to a thread-unsafe (apparently) API while( !PyTasklet_Paused(request->task) ) // prevent race (deadlock if this runs before the _Schedule call)
        {
              Sleep(0); // yield
        }

        Sleep(2); // LOSE THE RACE
        PyTasklet_Insert( request->task );
        LeaveCriticalSection( &stacklessLock );
}

it works, 5000 tasklets running full speed with 16 worker threads, all busy (no logging or anything, just pounding the interface) the mutex I should have put in to begin with, but the Sleep(2); is also critical it seems.

No way I'm leaving it that delicate.

So question is, what do I need to lose the race to? I am up to my armpits in stackless code, have tried some pretty ghastly things, such as adding a global flag that is set during the initial _Schedule() until it is released at the end of slp_transfer.. really figured that would work but it didn't. I'll keep plugging away but if any brainstorms thunder down please let me know.


On 6/10/2010 11:46 AM, Chris wrote:
I must be doing something silly and wrong, hopefully I can get some help from this list. I am writing a blocking call in the c api which is serviced by a [pool] of other threads, of course when the call is made I want to let stackless continue processing, so I did this, which works great:


PyObject* getData(PyObject *self, PyObject *args)
{
    // blah blah construct request on the heap
    request->task = PyStackless_GetCurrent();
queueRequest( request ); // this will get picked up by the thread pool PyStackless_Schedule( request->task ); // away it goes back into python-land

Py_DECREF( request->task ); // if we got here its because we were woken up

     // blah blah construct response and return
}


The thread pool does this:


worker()
{
// blah blah wait on queue and get a job and do some work waiting for awhile (or returning immediately)

while( !PyTasklet_Paused(request->task) ) // prevent race (deadlock if this runs before the _Schedule call)
        {
              Sleep(0); // yield
        }

        PyTasklet_Insert( request->task );
}


This works just fine. Until I stress it. this program from python crashes instantly in unpredicatbale (corrupt memory) ways:

import stackless
import dbase

def test():
    while 1:
        dbase.request()

for i in range( 10 ):
    task = stackless.tasklet( test )()
while 1:
    stackless.schedule()


BUT if I change that range from 10 to 1? runs all day long without any problems. Clearly I am doing something that isn't thread safe. but what? I've tried placing mutexes around the PyTask_ calls but since schedule doesn't normally return thats not possible everywhere, If I add Sleep's it helps, in fact if I make them long enough it fixes the problem and all 10 threads run concurrently.

I assume PyTasklet_Schedule()/_Insert() are meant to be used this way, (ie- multiple threads) can anyone tell me which stupid way I have gone wrong?


_______________________________________________
Stackless mailing list
[email protected]
http://www.stackless.com/mailman/listinfo/stackless



_______________________________________________
Stackless mailing list
[email protected]
http://www.stackless.com/mailman/listinfo/stackless

Reply via email to