2013-05-16 10 views
7

Właściwie używam visual C++, aby spróbować powiązać funkcje lua jako wywołania zwrotne dla zdarzeń gniazda (w innym wątku). Inicjuję rzeczy lua w jednym wątku, a gniazdo jest w innym wątku, więc za każdym razem, gdy gniazdo wysyła/odbiera wiadomość, wywołuje funkcję lua, a funkcja lua określa, co należy zrobić zgodnie ze znacznikiem wewnątrz wiadomość.Czy wywołanie funkcji lua (jako wywołania zwrotnego) z innego wątku jest wystarczająco bezpieczne?

Więc moje pytania to:

  1. Odkąd przechodzą ten sam stan Lua Lua do funkcji, jest to bezpieczne? Czy to nie wymaga jakiejś ochrony? Funkcje lua są wywoływane od innego theada, więc myślę, że mogą być wywołane jednocześnie.

  2. Jeśli to nie jest bezpieczne, jakie jest rozwiązanie tego przypadku?

Odpowiedz

2

Nie jest bezpiecznie oddzwonić asynchronicznie do stanu Lua.

Istnieje wiele sposobów radzenia sobie z tym problemem. Najpopularniejszy z nich to rodzaj głosowania.

Niedawny rodzajowy biblioteki synchronizacji DarkSideSync

Popularnym wiązanie z libev Lua jest lua-ev

This SO answer zaleca Lua Lanes z LuaSocket.

+0

Czy możesz wyjaśnić różnicę między Luan Lanes i DarkSideSync? DarkSideSync ma małe przykłady i nie wiem jak używać DarkSideSync –

+1

Lanes zapewnia typ danych, Lindas, które mogą być bezpiecznie współdzielone między pasami, asynchronicznymi stanami Lua. DarkSideSync koncentruje się bardziej na powiadamianiu i komunikacji między Lua i asynchronicznymi bibliotekami C. –

+0

Dziękuję Doug. –

1
  1. Nie jest bezpiecznie wywoływać funkcję w jednym stanie Lua jednocześnie w wielu wątkach.

  2. Miałem do czynienia z tym samym problemem, ponieważ w mojej aplikacji wszystkie podstawowe informacje, takie jak komunikacja, są obsługiwane przez C++, a cała logika biznesowa jest zaimplementowana w Lua. To, co robię, to utworzenie puli stanów Lua o numerach , które są tworzone i inicjowane na zasadzie przyrostowej (gdy nie ma wystarczającej liczby stanów, należy je utworzyć i zainicjować za pomocą wspólnych funkcji/obiektów). To działa tak:

    • Gdy przyłącze musi wywołać funkcję Lua, sprawdza się wystąpienie stanu Lua, inicjuje konkretne globalnych (ja nazywam to kontekst wątku/gra) w oddzielnym (proxy) tabela globalna, która zapobiega zanieczyszczaniu oryginalnego globalnego kodu, ale jest indeksowana przez oryginalną globalną
    • Zadzwoń do funkcji Lua.
    • Sprawdź stan Lua z powrotem do puli, gdzie jest przywracany do stanu "gotowy" (usuń tabela globalna proxy)

Myślę, że to podejście byłoby dobrze dopasowane również do twojej sprawy. Pula sprawdza każdy stan (na podstawie przedziału czasu), kiedy był ostatnio wyewidencjonowany. Gdy różnica czasu jest wystarczająco duża, niszczy stan, aby zachować zasoby i dostosować liczbę aktywnych stanów do bieżącego obciążenia serwera. Stan, który jest wyewidencjonowany, jest ostatnio używany wśród dostępnych stanów.

Są pewne rzeczy, które trzeba wziąć pod uwagę przy wdrażaniu takiego basen: wymaga

  • Każde państwo być wypełniane tych samych funkcji i zmiennych globalnych, co zwiększa zużycie pamięci.
  • Wdrażanie górnego limitu dla liczby stanów w puli
  • Zapewnienie, że wszystkie globale w każdym stanie są w stanie spójnym, jeśli się zdarzą (w tym miejscu zalecam umieszczanie tylko statycznych globów, a wypełnianie dynamicznych podczas sprawdzania poza stanem)
  • Dynamiczne ładowanie funkcji. W moim przypadku istnieje wiele tysięcy funkcji/procedur, które można nazwać w Lua. Posiadanie ich stale ładowanych we wszystkich stanach byłoby ogromnym marnotrawstwem. Zamiast tego trzymam ich kod bajtowy skompilowany po stronie C++ i je ładuję w razie potrzeby. Okazuje się, że w moim przypadku nie ma to wpływu na wydajność, ale twój przebieg może się różnić. Jedną rzeczą, o której trzeba pamiętać, jest załadowanie ich tylko raz. Powiedzmy, że wywołujesz skrypt, który musi wywołać inną dynamicznie ładowaną funkcję w pętli. Następnie powinieneś wczytać tę funkcję jako lokalną przed pętlą. Gdyby było inaczej, byłby to ogromny hit wydajnościowy.

Oczywiście to tylko jeden pomysł, ale okazał się najlepiej dla mnie odpowiedni.

+0

To dobry pomysł. Ale jakikolwiek kod open source/shared, jeśli to możliwe? –

+0

@MickeyShine - Nie mogę dać ci niczego, co jest prawdą dla Lua, ale możesz rzucić okiem na "mysql ++" implementację pul połączeń, która działa mniej więcej w ten sam sposób. [Pula połączeń] (http://tangentsoft.net/mysql++/doc/html/refman/classmysqlpp_1_1ConnectionPool.html) –

1
  1. To nie jest bezpieczne, jak inni wspomniano
  2. Zależy od usecase

rozwiązanie Najprostszy wykorzystuje globalną blokadę za pomocą makra lua_lock i lua_unlock. To użyłoby jednego stanu Lua, zablokowanego przez pojedynczy muteks. Dla małej liczby połączeń zwrotnych może to wystarczyć, ale w przypadku większego ruchu prawdopodobnie nie będzie to spowodowane poniesionymi kosztami.

Gdy potrzebujesz lepszej wydajności, stanowy basen Lua wspomniany przez W.B. to dobry sposób na poradzenie sobie z tym. Trickiest część tutaj znaleźć synchronizację danych globalnych w wielu stanach.

, wspomniana przez Douga, jest przydatna w przypadkach, gdy główna pętla aplikacji znajduje się po stronie Lua. Napisałem to specjalnie w tym celu. W twoim przypadku nie wydaje się to być odpowiednie. Powiedziawszy to; w zależności od twoich potrzeb możesz rozważyć zmianę aplikacji, aby główna pętla znajdowała się po stronie Lua. Jeśli obsługujesz tylko gniazda, możesz użyć LuaSocket i żadna synchronizacja nie jest wymagana. Ale oczywiście zależy to od tego, co jeszcze robi aplikacja.

Powiązane problemy