2016-04-08 14 views
7

Ich stehe vor einem interessanten Problem, das nur unter Windows passiert, während auf Linux/Mono alles gut funktioniert. Ich habe einen C++ - Wrapper um die MySQL Cluster NDB API-Bibliothek erstellt, die ich aus C# -Code über P/Invoke heraus aufruft. Bisher habe ich drei Methoden:MySQL NDB API AccessViolationException

  1. init() die die Umwelt initialisiert und gibt einen Handle
  2. read(), die die Daten aus der Datenbank liest mit dem Griff
  3. release() die frei Ressourcen

init() funktioniert in jedem Setup gut. Jedoch read() wirft AccessViolationException, aber nur unter Windows und nur für den Fall, wenn init() in einem Thread und read() in einem anderen aufgerufen wird. Wenn wir alles in einem einzigen Thread machen, funktioniert es! Irgendwelche Gedanken über die mögliche Ursache würden geschätzt werden.

aktualisiert 2016.12.04 - das gleiche Verhalten wurde mit einem einfachen C++ Testprogramm bemerkt, wo init() in einem Thread und read() in einem anderen aufgerufen wird. Daher hat der Fehler nichts mit C#/C++ - Interop, es ist etwas innerhalb NDB API-Bibliothek, die here (lib Ordner, mysqlclient.lib und ndbclient_static.lib) heruntergeladen werden kann.

C# -Code:

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++ Code: (basierend auf Beispiele aus den official documentation):

#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

Meinst du 'ndb_api_init' von' init'? – Ripple

+0

@Ripple Ja, ich habe einen Fehler gemacht, während c/p-Code. Bearbeitet, tnx. –

+0

Und wenn Sie das gleiche tun (d. H. Init starten und dann in verschiedenen Threads einlesen) in C++, ohne C# -Wrapper zu verwenden, was wäre das Ergebnis? – Evk

Antwort

2

Mit Hilfe von MySQL Cluster Mailing-Liste, habe ich eine Abhilfe für dieses Problem gefunden .

Wenn Sie Daten über NDB API in einem Thread anders als die, lesen möchten, wo Sie ndb_init() aufgerufen und erhalten Ndb_cluster_connection, ist es notwendig, mysql_thread_init() am Anfang des anderen Thread zu nennen. Dies ist jedoch kein erwartetes Verhalten, noch ist dies dokumentiert, daher habe ich a bug eingereicht.