2016-04-08 23 views
7

Sadece Windows'ta meydana gelen ilginç bir sorunla karşı karşıyayım, Linux/Mono'da her şey iyi çalışıyor. C# kodundan P/Invoke ile aradığım MySQL Cluster NDB API kütüphanesi etrafında bir C++ sarmalayıcısı oluşturdum. Şimdiye kadar üç yöntem vardır: kaynak MySQL NDB API AccessViolationException

init() serbest bırakır kolu

  • release() kullanarak veritabanından veri okuyan bir kolu
  • read() çevreyi başlatır ve döner

    1. init() her kurulumda iyi çalışıyor. Ancak, read(), AccessViolationException'u atar, ancak yalnızca Windows'ta ve yalnızca init() bir iş parçacığında ve read() diğerinde çağrıldığında oluşur. Her şeyi tek bir iş parçacığında yaparsak işe yarıyor! Olası neden hakkında herhangi bir düşünce takdir edilecektir.

      Güncelleme 2016/12/04 - aynı davranış init() bir iplik diğerinde read() çağrılır basit C++ test programı ile fark edilmiştir. Bu nedenle, hatanın C#/C++ interop ile hiçbir ilgisi yoktur, bu, here (lib klasörü, mysqlclient.lib ve ndbclient_static.lib klasörü) indirilebilen NDB API kitaplığı içindeki bir şeydir.

      C# kodu :

      private const string ndbapi = "ndb"; 
      
      [DllImport(ndbapi)] 
      public extern static IntPtr init(IntPtr conn_string); 
      
      [DllImport(ndbapi)] 
      public extern static void read(IntPtr ndb_cluster_conn); 
      
      [DllImport(ndbapi)] 
      public extern static void release(IntPtr ndb_cluster_conn, IntPtr char_arr_ptr); 
      
      private static IntPtr handle; 
      
      private static void InitNdb() { 
          unsafe { 
           fixed (byte* conn_buf = Encoding.UTF8.GetBytes("node1:1186")) {    
            handle = ndb_api_init(new IntPtr(conn_buf)); 
           } 
          } 
      } 
      static void Main(string[] args) { 
          Thread t = new Thread(InitNdb);// IF I CALL InitNDB IN THE SAME THREAD, EVERYTHING WORKS 
          t.Start(); 
          .. //waiting for Thread t to complete... 
          IntPtr bytes_read = read(handle); 
          ... 
      } 
      

      C++ kodu: (official documentation örneklerle dayanarak): MySQL Cluster posta listesinin yardımıyla

      #if defined(WIN32) 
      
      #define DLLEXPORT __declspec(dllexport) 
      #define CALLCV __stdcall 
      
      #else 
      
      #define DLLEXPORT __attribute__((visibility("default"))) 
      #define CALLCV __attribute__((cdecl)) 
      
      #endif 
      .. 
      extern "C" DLLEXPORT Ndb_cluster_connection* CALLCV init(char* connection_string) { 
      
          ndb_init(); 
      
          // Object representing the cluster 
          Ndb_cluster_connection* cluster_connection = new Ndb_cluster_connection(connection_string); 
      
          if (cluster_connection->connect(3, 2, 1)) { 
           std::cout << "Cluster management server not ready,error:" << cluster_connection->get_latest_error_msg() << "\n"; 
           exit(-1); 
          } 
          if (cluster_connection->wait_until_ready(10, 0) < 0) { 
           std::cout << "Cluster not ready within 10 secs, error:" << cluster_connection->get_latest_error_msg() << std::endl; 
          } 
      
          return cluster_connection; 
      } 
      extern "C" DLLEXPORT char** CALLCV read(Ndb_cluster_connection* cluster_connection) { 
          Ndb *ndb_obj = new Ndb(cluster_connection, db_name); 
          if (ndb_obj->init()) { 
           std::cout << "Error while initializing Ndb " << std::endl; 
          } 
      
          const NdbDictionary::Dictionary* dict = ndb_obj->getDictionary(); 
          const NdbDictionary::Table *table = dict->getTable("table_name"); <-- THIS IS THE LINE THAT THROWS ACCESS VIOLATION EXCEPTION 
          .. 
      } 
      
  • +0

    Bunu mu demek istediniz: ndb_api_init' by 'init'? – Ripple

    +0

    @Ripple Evet, c/p kodu yaparken hata yaptım. Düzenlendi, tnx. –

    +0

    Ve eğer C# sarmalayıcısını kullanmadan C++ 'da aynı işlemi yaparsanız (yani farklı konuları okuyorsanız), sonuç ne olur? – Evk

    cevap

    2

    , bu soruna yönelik bir çözüm bulduk . Eğer ndb_init() çağrılan ve Ndb_cluster_connection elde birinden farklı dizisindeki NDB API aracılığıyla veri okumak istiyorsanız

    , o başka iş parçacığı başında mysql_thread_init() aramak gereklidir. Ancak, bu beklenen bir davranış değildir ve belgelenmez, böylece a bug başvurusunda bulundum.