> -----Original Message-----
> From: python-ideas-bounces+kristjan=ccpgames....@python.org
> [mailto:python-ideas-bounces+kristjan=ccpgames....@python.org] On
> Behalf Of Sturla Molden
> Sent: 20. október 2009 22:13
> To: python-id...@python.org
> Subject: Re: [Python-ideas] Remove GIL with CAS instructions?
> 
> 
> - The GIL has consequences on multicore CPUs that are overlooked:
> thread
> switches are usually missed at check intervals. This could be fixed
> without removing the GIL: For example, there could be a wait-queue for
> the GIL; a thread that request the GIL puts itself in the back.
> 


This depends entirely on the platform and primitives used to implement the GIL.
I'm interested in windows.  There, I found this article:
http://fonp.blogspot.com/2007/10/fairness-in-win32-lock-objects.html
So, you may be on to something.  Perhaps a simple C test is in order then?

I did that.  I found, on my dual-core vista machine, that running "release", 
that both Mutexes and CriticalSections behaved as you describe, with no 
"fairness".  Using a "semaphore" seems to retain fairness, however.
"fairness" was retained in debug builds too, strangely enough.

Now, Python uses none of these.  On windows, it uses an "Event" object coupled 
with an atomically updated counter.  This also behaves fairly.

The test application is attached.


I think that you ought to sustantiate your claims better, maybe with a specific 
platform and using some test like the above.

On the other hand, it shows that we must be careful what we use.  There has 
been some talk of using CriticalSections for the GIL on windows.  This test 
ought to show the danger of that.  The GIL is different than a regular lock.  
It is a reverse-lock, really, and therefore may need to be implemented in its 
own special way, if we want very fast mutexes for the rest of the system (cc to 
python-dev)

Cheers,

Kristján
// giltest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdlib.h>
#include <process.h>

#include <windows.h>
#include <assert.h>
#include <vector>

#define EVENT

#ifdef EVENT
LONG gilcount;
HANDLE gil;
void CreateGIL(){
        gilcount = 0;
        gil = CreateEvent(0, FALSE, FALSE, 0) ;
}

void ClaimGIL() {
        if (InterlockedIncrement(&gilcount) > 1) {
                DWORD r = WaitForSingleObject(gil, INFINITE);
                assert(r == WAIT_OBJECT_0);
        }
}

void ReleaseGIL() {
        if (InterlockedDecrement(&gilcount) > 0) {
                BOOL ok = SetEvent(gil);
                assert(ok);
        }
}
#endif 



#ifdef MUTEX
HANDLE gil = 0;
void CreateGIL(){
        gil = CreateMutex(0, FALSE, 0);
}

void ClaimGIL() {
        DWORD r = WaitForSingleObject(gil, INFINITE);
        assert(r == WAIT_OBJECT_0);
}

void ReleaseGIL() {
        BOOL ok = ReleaseMutex(gil);
        assert(ok);
}
#endif

#ifdef SEMAPHORE
HANDLE gil = 0;
void CreateGIL(){
        gil = CreateSemaphore(0,1, 1, 0);
}

void ClaimGIL() {
        DWORD r = WaitForSingleObject(gil, INFINITE);
        assert(r == WAIT_OBJECT_0);
}

void ReleaseGIL() {
        BOOL ok = ReleaseSemaphore(gil, 1, 0);
        assert(ok);
}
#endif

#ifdef CRIT
CRITICAL_SECTION gil;
void CreateGIL(){
        InitializeCriticalSection(&gil);
}

void ClaimGIL() {
        EnterCriticalSection(&gil);
}

void ReleaseGIL() {
        LeaveCriticalSection(&gil);
}
#endif


void FlashGIL() {
        DWORD id = GetCurrentThreadId();
        printf("thread %10d flashing GIL\n", id);
        ReleaseGIL();
        ClaimGIL();
        printf("thread %10d reclaims GIL\n", id);
}



void DoWork(int rounds)
{
        DWORD id = GetCurrentThreadId();
        while (rounds--) {
                int sum = 0;
                int n = rand();
                n += RAND_MAX;
                printf("thread %10d working %d units\n", id, n);
                for (int i=0; i<n; ++i)
                        sum += i;
                printf("thread %10d worked %d units: %d\n", id, n, sum);
                FlashGIL();
        }
}
                
unsigned __stdcall threadfunc(void *arg) {
        int rounds = (int)arg;
        DWORD id = GetCurrentThreadId();
        printf("thread %10d starting\n", id);
        ClaimGIL();
        printf("thread %10d got GIL\n", id);
        DoWork(rounds);
        ReleaseGIL();
        return 0;
}


HANDLE StartThread(int rounds)
{
        uintptr_t h = _beginthreadex(0, 0, threadfunc, (void*)rounds, 0, 0);
        assert(h != -1L);
        return (HANDLE) h;
}


int _tmain(int argc, _TCHAR* argv[])
{
        int nThreads = 2;
        int nRounds = 10;
        CreateGIL();
        std::vector<HANDLE> threads;
        for (int i = 0; i<nThreads; i++)
                threads.push_back(StartThread(nRounds));

        DWORD r = WaitForMultipleObjects(threads.size(), &threads[0], TRUE, 
INFINITE);
        getc(stdin);
}

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to