Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[C#] Garbage Collector - czy może zmienić adres tablicy?

czokus 04 Jun 2010 09:00 1509 5
  • #1
    czokus
    Level 17  
    Witam

    Mam pewną tablicę int tab[15][15] i w celu szybkiego przeglądania jej elementów po skosie (dla celów pewnej gry - wyszukiwanie 5 identycznych cyfr pod rząd) zrobiłem listę która trzyma wskaźniki do konkretnych elementów w formie jednowymiarowych tablic wskaźników (dla pojedynczego elementu listy przechowuję strukturę 4 linii przechodzących przez ten element - pionowej, poziomej i 2 skośnych). Całość działa bardzo dobrze, ale...tylko przez kilka ruchów. Przykładowo znajduje dokładnie 1 raz pięć takich samych cyfr pod rząd np w linii poziomej i następnie innej takiej linii już nie widzi... Czasem jest w stanie znaleźć 3 albo 4 takie linie...po czym oczywiście przestaje działać. Myślę że problem może być w tym że Garbage Collector może "przesunąć" tablicę tab[15][15] w inny fragment pamięci co powoduje że adresy elementów tej tablicy jakie zostały zapamiętane na liście stają się nieaktualne... Jednak nie wiem dokładnie czy takie zjawisko może zajść w C#? Jeśli tak to czy jest sposób aby zablokować adres takiej tablicy w pamięci - żeby Garbage Collector nie mógł jej przesunąć..

    Pozdrawiam
  • #2
    Biegal
    Level 14  
    Jest to z tego co mi wiadomo nie możliwe. Także błąd jest gdzieś indziej. Jeśli masz referencję do jakiegoś obszaru pamięci (w tym wypadku referencja tablicy) to GC tego nie ruszy.
  • #3
    gaskoin
    Level 38  
    to na pewno nie jest wina GC :) wklej może kod, to będzie łatwiej pomóc, bo tak to możemy tylko sypać w nieskończoność różnymi bezsensownymi wymyślunkami
  • #4
    czokus
    Level 17  
    Oki to zacznę po kawałku od początku...

    1) Tworzę sobie tablicę ruchy, która ma być odpowiednikiem planszy do gry...

    public static int[][] ruchy = new int[15][];


    2) Do tej tablicy tworzę drugą która jedynie przechowuje indeksy do listy - tablica indeksów wypełniona jest kolejnymi liczbami od 0 do 224...

    public static int[][] indeksy_Board = new int[15][];


    3) Tworzę pewną klasę której obiekty będę przechowywał na liście 225 elementów

    public class TypListy
            {
                public unsafe int*[] poziomo { get; set; }
                public unsafe int*[] pionowo { get; set; }
                public unsafe int*[] skosL { get; set; }
                public unsafe int*[] skosP { get; set; }
                public int[] zasieg { get; set; }
            }


    4) Tworzę listę elementów
    public static List<TypListy> BoardList = new List<TypListy>();


    5) Wypełniam listę odpowiednimi elementami tablicy ruchy w formie wskaźników

    public unsafe static void attak()
            {
                
                for (int i = 0; i < 15; i++) //x
                    for (int j = 0; j < 15; j++) //y
                    {
                        
                        int*[] _pionowo = new int*[9];
                        int*[] _poziomo = new int*[9];
                        int*[] _skosL = new int*[9];
                        int*[] _skosP = new int*[9];
    
                        int[] _zasieg = { 0, 0, 0, 0 };
    
                        int licznik = 0;
    
                        // wskaźniki na 1 element ustawiam żeby wszystkie na coś wskazywały ;P
                        fixed (int* pirat = &ruchy[0][0])
                        {
                            for (int www = 0; www < 9; www++)
                            {
                                _pionowo[www] = pirat;
                                _poziomo[www] = pirat;
                                _skosL[www] = pirat;
                                _skosP[www] = pirat;
                            }
                        }
                        
    
                        //==========================================
                        //pionowo
                        //==========================================
    
                        //od góry do ij
                        for (int x = 4; x >= 0; x--)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i - x][j])
                                {
                                    _pionowo[licznik] = adres;
                                    licznik++;
                                }
                            }
                            catch { };
                        }
    
    
                        //od ij+1 do dołu=============================
                        for (int x = 1; x < 5; x++)
                        {
                            try
                            {  
                                fixed (int* adres = &ruchy[i + x][j])
                                {
                                    _pionowo[licznik] = adres;
                                    licznik++;
                                }
                                
                            }
                            catch { };
                        }
    
                        _zasieg[0] = licznik;
                        
    
                        licznik = 0;
    
    
                        //==========================================
                        //poziomo
                        //==========================================
    
                        //od lewej do ij
                        for (int x = 4; x >= 0; x--)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i][j - x])
                                {
                                    _poziomo[licznik] = adres;
                                    licznik++;
                                }       
                            }
                            catch { };
                        }
    
    
                        // od ij+1 do prawej 4 elementy
                        for (int x = 1; x < 5; x++)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i][j + x])
                                {
                                    _poziomo[licznik] = adres;
                                    licznik++;
                                }   
                            }
                            catch { };
                        }
    
                        _zasieg[1] = licznik;
    
                        licznik = 0;
    
    
                        //==========================================
                        //skosL \
                        //==========================================
    
                        //od lewej góry do ij
                        for (int x = 4; x >= 0; x--)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i - x][j - x])
                                {
                                    _skosL[licznik] = adres;
                                    licznik++;
                                }
                            }
                            catch { };
                        }
    
    
                        // od ij do prawego dołu 4 elementy
                        for (int x = 1; x < 5; x++)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i + x][j + x])
                                {
                                    _skosL[licznik] = adres;
                                    licznik++;
                                }
                            }
                            catch { };
                        }
    
                        _zasieg[2] = licznik;
    
                        licznik = 0;
    
    
                        //==========================================
                        //skosP  /
                        //==========================================
    
                        //od prawej góry do ij
                        for (int x = 4; x >= 0; x--)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i - x][j + x])
                                {
                                    _skosP[licznik] = adres;
                                    licznik++;
                                }
                            }
                            catch { };
                        }
    
    
                        // od ij do lewego dołu 4 elementy
                        for (int x = 1; x < 5; x++)
                        {
                            try
                            {
                                fixed (int* adres = &ruchy[i + x][j - x])
                                {
                                    _skosP[licznik] = adres;
                                    licznik++;
                                }
                            }
                            catch { };
                        }
    
                        _zasieg[3] = licznik;
    
                        licznik = 0;
    
    
                        //=============================================
                        BoardList.Add(new TypListy { pionowo = _pionowo, poziomo = _poziomo, skosL = _skosL, skosP = _skosP, zasieg = _zasieg });
    
    
                    }
                
    
            }


    6) Teraz zrobiłem sobie metodę do sprawdzania czy konkretny element tablicy ruchy jest częścią kolejnych pięciu takich samych elementów pod względem wartość np = 1

    public int fastwinsearch(int numerek, int gracz)
            {
                int licznik = 0;
                int suma = 0;
                int zasiegaj = 0;
    
                //pionowo ====================================
                zasiegaj = BoardList[numerek].zasieg[0];
    
                if (zasiegaj >= 5)
                {
                    unsafe
                    {
                        while (suma < 5 && licznik < zasiegaj)
                        {
                            if (*BoardList[numerek].pionowo[licznik] == gracz) suma++;
                            else suma = 0;
                            licznik++;
                        }
                    }
    
                    if (suma == 5) return 5;
                    suma = 0;
                    licznik = 0;
                }
    
                //poziomo ====================================
                zasiegaj = BoardList[numerek].zasieg[1];
    
                if (zasiegaj >= 5)
                {
                    unsafe
                    {
                        while (suma < 5 && licznik < zasiegaj)
                        {
                            if (*BoardList[numerek].poziomo[licznik] == gracz) suma++;
                            else suma = 0;
                            licznik++;
                        }
                    }
    
                    if (suma == 5) return 5;
                    suma = 0;
                    licznik = 0;
                }
    
                //skosL ====================================
                zasiegaj = BoardList[numerek].zasieg[2];
    
                if (zasiegaj >= 5)
                {
                    unsafe
                    {
                        while (suma < 5 && licznik < zasiegaj)
                        {
                            if (*BoardList[numerek].skosL[licznik] == gracz) suma++;
                            else suma = 0;
                            licznik++;
                        }
                    }
    
                    if (suma == 5) return 5;
                    suma = 0;
                    licznik = 0;
                }
    
                //skosP ====================================
                zasiegaj = BoardList[numerek].zasieg[3];
    
                if (zasiegaj >= 5)
                {
                    unsafe
                    {
                        while (suma < 5 && licznik < zasiegaj)
                        {
                            if (*BoardList[numerek].skosP[licznik] == gracz) suma++;
                            else suma = 0;
                            licznik++;
                        }
                    }
    
                    if (suma == 5) return 5;
                    suma = 0;
                    licznik = 0;
                }
    
    
    
                return 0;
            }


    7) No i mam też jakąś prostą metodę czyszczącą planszę
    public void czysc()
            {
                for (int i = 0; i < 15; i++)
                    for (int j = 0; j < 15; j++)
                    {
                        buttony[i][j].BackColor = Color.FromArgb(171, 156, 156);
                        buttony[i][j].Text = "";
                        ruchy[i][j] = 0;
                    }
            }


    8) Póki co wstawiam sobie na planszy liczby 1 i po każdym wstawieniu sprawdzam czy udało się utworzyć 5 w linii - jeśli tak to wyświetlam napis że wygrana i czyszczę planszę i dalej chcę sobie powstawiać tak samo te 1 ale już nie działa....
    public void buttony_Click(object sender, EventArgs e)
            {
    
    
                if (flaga)
                {
                    flaga = false; //blokada
    
                    for (int i = 0; i < 15; i++)
                        for (int j = 0; j < 15; j++)
                        {
                            if (sender == buttony[i][j])
                            {
                                //czysc();   
                                buttony[i][j].Text = "O";
                                buttony[i][j].BackColor = Color.FromArgb(100, 126, 56);
                                ruchy[i][j] = 1;
    
                                if (fastwinsearch(indeksy_Board[i][j], 1) == 5)
                                {
                                    MessageBox.Show("Znaleziono wygraną!!");
                                    czysc();
                                }
    
                            }
                        }
    
    
                    flaga = true; //zwolnienie blokady
                }
    
    
            }
    







    Znalazłem takie info w necie:

    Quote:
    fixed : pozwala blokować obiekty (zmienne) w pamięci. Informuje system, by nie zmieniał położenia w pamięci danego obiektu (standardowo system dowolnie umieszcza i przesuwa obiekty w obrębie sterty - jednak gdybyśmy wskazywali na jakiś obiekt wskaźnikiem, a w międzyczasie zmienił by on swoje położenie, doprowadziło by to do błędów).


    Tak jak ja to rozumiem to faktycznie GC blokuje możliwość przesunięcia w pamięci tablicy, ale tylko na czas gdy jesteśmy wewnątrz bloku fixed natomiast po wyjściu z niego tablica dalej może być przenoszona.. W moim przypadku na samym początku uruchamiania programu następuje uzupełnienie wskaźników na liście i wtedy faktycznie jest na chwilę blokowana tablica. Natomiast później wskaźniki nie są w żaden sposób uaktualniane więc jeśli GC przesunie sobie w inne miejsce taką tablicę to adresy na jakie wskazują stają się nieaktualne i moja metoda fastwinsearch nie jest w stanie nic znaleźć... Takie jest moje zdanie, ale mogę się mylić... Co o tym myślicie?
  • #5
    Biegal
    Level 14  
    Przyznam, że nie zagłębiłem się jeszcze w logikę kodu, ale czemu to wszystko robisz na wskaźnikach? Jakiś nakaz? Chyba, że jest tam jakiś element, którego nie da się wykonać inaczej (a wątpię), którego nie zauważyłem.
  • #6
    czokus
    Level 17  
    Kwestia wydajnościowa - ta funkcja będzie uruchamiana przez algorytm alpha-beta (taka sztuczna inteligencja komputera) setki tysięcy razy a nawet miliony więc wyszukiwanie wygranej musi być realizowane bardzo szybko - każdy dodatkowy warunek będzie powodował wydłużenie obliczeń... Wskaźniki to chyba najwydajniejsza metoda..