Re[8]: Заполнить DWORD нулями?
От: Аноним  
Дата: 18.08.08 22:54
Оценка:
P>>На любое не получится, если память общая для всех потоков.
А>Вот, оптимизированный вариант. Быстро обнуляет все DWORDы в указанном процессе. Масштабируется на любое количество процессоров.
Еще и отрефакторил

#include <windows.h>
#include <queue>
#include <vector>
#include <algorithm>


class IThread
{
public:
    virtual void ThreadRoutine() = 0;
};

class ThreadsPool
{
    typedef std::vector<HANDLE>        Handles;
    IThread *_ithread;
    Handles _handles;
    
    static DWORD CALLBACK StaticThreadRoutine(void *p)
    {
        ((ThreadsPool*)p)->_ithread->ThreadRoutine();
        return 0;
    }

public:
    ThreadsPool(IThread *ithread) throw (std::runtime_error)
        : 
      _ithread(ithread) 
    {
        DWORD_PTR max_affinity = 0x01, sys_affinity;
        if (!::GetProcessAffinityMask(::GetCurrentProcess(), &max_affinity, &sys_affinity))
            max_affinity = 0x01;
        
        for(DWORD_PTR i = 1; i; i<<=1)
        {
            if (max_affinity&i)
            {
                DWORD tid;
                HANDLE trd = ::CreateThread(NULL, 0, StaticThreadRoutine, this, CREATE_SUSPENDED, &tid);
                if (trd)
                {
                    ::SetThreadAffinityMask(trd, i);
                    _handles.push_back(trd);
                }
            }
        }

        if (_handles.empty())
            throw std::runtime_error("failed to create threads");
        printf("%u threads initialized\n", _handles.size());
    }
    void Complete()
    {
        if (_handles.empty())
            throw std::runtime_error("already complete");
        
        std::for_each(_handles.begin(), _handles.end(), ::ResumeThread);            
        for(size_t i=0; i<_handles.size(); i+=MAXIMUM_WAIT_OBJECTS)
        {
            ::WaitForMultipleObjects(min(_handles.size()-i, MAXIMUM_WAIT_OBJECTS), &_handles[i], TRUE, INFINITE);
        }
        std::for_each(_handles.begin(), _handles.end(), ::CloseHandle);
        _handles.clear();
    }

};


class AbsoluteZero : private IThread
{
    HANDLE _process;
    
    typedef std::queue<MEMORY_BASIC_INFORMATION>    MemoryRanges;

    MemoryRanges _mem_ranges;
    CRITICAL_SECTION _cs;

    void ZeroThatDwords(PDWORD ptr, SIZE_T count)
    {
        for(;count;--count,++ptr)
        {
            DWORD etalon = 0, written;
            ::WriteProcessMemory(_process, ptr, &etalon, sizeof(etalon), &written);
        }
    }

    virtual void ThreadRoutine()
    {
        for(;;)
        {
            MEMORY_BASIC_INFORMATION mbi;
            ::EnterCriticalSection(&_cs);
            bool exit = _mem_ranges.empty();
            if (!exit)
            {
                mbi = _mem_ranges.front();
                _mem_ranges.pop();
            }
            ::LeaveCriticalSection(&_cs);
            if (exit) break;

            ZeroThatDwords((PDWORD)mbi.BaseAddress, mbi.RegionSize/sizeof(DWORD));
        }
    }
    

    void QueryMemory()
    {
        for(PCHAR ptr = NULL;ptr<(PCHAR)MAXLONG_PTR;)
        {
            MEMORY_BASIC_INFORMATION mbi = {0};
            if (::VirtualQueryEx(_process, ptr, &mbi, sizeof(mbi)) && ((PCHAR)mbi.BaseAddress+mbi.RegionSize)>ptr) 
            {
                if ( mbi.State!=MEM_FREE && mbi.State!=MEM_RESERVE && 
                    (mbi.Protect==PAGE_READWRITE || mbi.Protect==PAGE_WRITECOPY || 
                    mbi.Protect==PAGE_EXECUTE_READWRITE || mbi.Protect==PAGE_EXECUTE_WRITECOPY))
                {
                    _mem_ranges.push(mbi);
                }
                ptr = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
            }
            else
                ptr+= 0x1000;
        }
    }
    
public:

    AbsoluteZero(DWORD pid) throw (std::runtime_error)
    {
        _process = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, pid);
        if (!_process)
        {
            throw std::runtime_error("failed to capture process handle");
        }
        ::InitializeCriticalSection(&_cs);
    }

    virtual ~AbsoluteZero()
    {
        ::DeleteCriticalSection(&_cs);
        ::CloseHandle(_process);
    }

    
    void ZeroAllDwords()
    {
        QueryMemory();
        printf("%u memory regions found\n", _mem_ranges.size());
        
        try
        {
            ThreadsPool(this).Complete();
        }
        catch (std::runtime_error &e) 
        {
            printf("Threads error: %s [%u] will use single-thread model\n", e.what(), ::GetLastError());
            ThreadRoutine();
        }
    }
};

int main(int argc, const char *argv[])
{
    try
    {
        if (argc!=2)
            throw std::runtime_error("You should specify one additional parameter - process wich DWORDs must be zeroed\n");

        DWORD ticks = ::GetTickCount();
        AbsoluteZero(atoi(argv[1])).ZeroAllDwords();
        printf("Zeroing complete in %u msec\n", ::GetTickCount()-ticks);
    }
    catch(std::runtime_error &e)
    {
        printf("Error: %s [%u]\n", e.what(), ::GetLastError());
    }
    
    return 0;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.