Quantcast

Mono in Ubuntu thread

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Mono in Ubuntu thread

howard.rubin
My program (below) works on Fedora 22 or if I call the thread function directly from main(). But if I launch the mono calls in a thread on Ubuntu 16.04, it asserts like this. Am I doing something wrong?
Howard Rubin

Output:

$ rm monotest.dll ; make ; ./monotest
Mono C# compiler version 4.8.0.0
mcs monotest.cs /out:monotest.dll /target:library
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
g++ monotest.cpp -o monotest -g3 -std=c++11 `pkg-config --cflags --libs mono-2`
MySum(1,2) => 3
* Assertion at mono-threads-posix.c:265, condition `info->handle' not met

Aborted (core dumped)
$

///////////////////////////////
// monotest.cpp
#include <thread>
#include <sstream>
#include <iostream>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>

MonoDomain* domain;
MonoImage* image;

MonoObject* Create(void* args[],
                   const char* namespacename, const char* classname, const char* paramnames);
MonoObject* Call(MonoObject* theObject, void* args[],
                 const char* namespacename, const char* classname, const char* functionsignature);

void Thread() {
    domain = mono_jit_init("monotest.dll");
    MonoAssembly* assembly = mono_domain_assembly_open(domain, "monotest.dll");
    image = mono_assembly_get_image(assembly);

    int one = 1, two = 2;
    void* args[] = { &one, &two };

    MonoObject* MyClass = Create(nullptr, "MyNamespace", "MyClass", "");

    Call(MyClass, args, "MyNamespace", "MyClass", "MySum (int,int)");

    mono_jit_cleanup(domain);
}

int main() {
    //Thread();
    std::thread t(Thread);
    t.join();

}

MonoObject* Call(MonoObject* theObject, void* args[],
                 const char* namespacename, const char* classname, const char* functionsignature) {

    MonoClass* theClass = mono_class_from_name(image, namespacename, classname);
    if (theClass == nullptr) {
        std::cout << "mono_class_from_name(\"" << namespacename << "\",\"" << classname
                  << "\") returned null for \"" << functionsignature << '"' << std::endl;
        return nullptr;
    }

    std::ostringstream os; // e.g. "DocumentFormat.OpenXml.Packaging.WordprocessingDocument:AddMainDocumentPart()"
    os << namespacename << '.' << classname << ':' << functionsignature;
    std::string str = os.str();
    MonoMethodDesc* theDesc = mono_method_desc_new(str.c_str(), true);
    if (theDesc == nullptr) {
        std::cout << "mono_method_desc_new(" << str << ") returned null for \""
                  << functionsignature << '"' << std::endl;
        return nullptr;
    }

    MonoMethod* theMethod = mono_method_desc_search_in_class(theDesc, theClass);
    if (theMethod == nullptr) {
        std::cout << "mono_method_desc_search_in_class() returned null for \""
                  << functionsignature << '"' << std::endl;
        return nullptr;
    }

    MonoObject* exception = NULL;
    MonoObject* returnValue = mono_runtime_invoke(theMethod, theObject, args, &exception);
    if (exception)
        mono_print_unhandled_exception(exception);

    return returnValue;
}

static bool ErrorMessage(const void* value, const char* function, int line, const char* sourcefile) {
    if (value == nullptr)
        std::cout << function << "() returned null (line " << line << " of file " << sourcefile << std::endl;
    return value == nullptr;
}
MonoObject* Create(void* args[],
                   const char* namespacename, const char* classname, const char* paramnames) {

    MonoClass* theClass = mono_class_from_name(image, namespacename, classname);
    if (ErrorMessage(theClass, "mono_class_from_name", __LINE__, __FILE__))
        return nullptr;

    std::ostringstream os; // e.g. "DocumentFormat.OpenXml.Wordprocessing.Text:.ctor(string)"
    os << namespacename << '.' << classname << ":.ctor (" << paramnames << ')';
    std::string str = os.str();
    MonoMethodDesc* theDesc = mono_method_desc_new(str.c_str(), false);
    if (ErrorMessage(theDesc, "mono_method_desc_new", __LINE__, __FILE__))
        return nullptr;

    MonoMethod* theCtor = mono_method_desc_search_in_class(theDesc, theClass);
    if (ErrorMessage(theCtor, "mono_method_desc_search_in_class", __LINE__, __FILE__))
        return nullptr;

    MonoObject* theObject = mono_object_new(domain, theClass);
    if (ErrorMessage(theObject, "mono_object_new", __LINE__, __FILE__))
        return nullptr;

    MonoObject* exception = NULL;
    mono_runtime_invoke(theCtor, theObject, args, &exception); // returns NULL
    if (exception)
        mono_print_unhandled_exception(exception);

    return theObject;
}

////////////////////////
// monotest.cs
namespace MyNamespace  {

    public class MyClass {
        public MyClass() { }

        public void MySum(int arg1, int arg2) {
            System.Console.WriteLine("MySum(" + arg1 + "," + arg2 + ") => " + (arg1 + arg2));
        }
    }
}

###################
# Makefile
monotest : monotest.cpp monotest.dll Makefile
        @g++ --version | head -1
        g++ $< -o $@ -g3 -std=c++11 `pkg-config --cflags --libs mono-2`

monotest.dll : monotest.cs
        @mcs --version
        mcs $< /out:$@ /target:library


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Mono in Ubuntu thread

howard.rubin
I was able to shorten the C part of my example to almost nothing:

// monotest.cpp
#include <thread>
#include <mono/jit/jit.h>

void Thread() {
    MonoDomain* domain = mono_jit_init("monotest.dll");
    mono_jit_cleanup(domain);
}

int main() {
    //Thread();
    std::thread t(Thread);
    t.join();
}

howard.rubin wrote
My program (below) works on Fedora 22 or if I call the thread function directly from main(). But if I launch the mono calls in a thread on Ubuntu 16.04, it asserts like this. Am I doing something wrong?
Howard Rubin

Output:

$ rm monotest.dll ; make ; ./monotest
Mono C# compiler version 4.8.0.0
mcs monotest.cs /out:monotest.dll /target:library
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
g++ monotest.cpp -o monotest -g3 -std=c++11 `pkg-config --cflags --libs mono-2`
MySum(1,2) => 3
* Assertion at mono-threads-posix.c:265, condition `info->handle' not met

Aborted (core dumped)
$

////////////////////////
// monotest.cs
namespace MyNamespace  {

    public class MyClass {
        public MyClass() { }

        public void MySum(int arg1, int arg2) {
            System.Console.WriteLine("MySum(" + arg1 + "," + arg2 + ") => " + (arg1 + arg2));
        }
    }
}

###################
# Makefile
monotest : monotest.cpp monotest.dll Makefile
        @g++ --version | head -1
        g++ $< -o $@ -g3 -std=c++11 `pkg-config --cflags --libs mono-2`

monotest.dll : monotest.cs
        @mcs --version
        mcs $< /out:$@ /target:library
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Mono in Ubuntu thread

howard.rubin
In reply to this post by howard.rubin
It turns out there's much to know to get threading to work in mono. mono_thread_create() for one thing seems to work.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Mono in Ubuntu thread

howard.rubin
The documentation for using threads in mono is woefully inadequate, but with experimentation threads can be made to work.

One way is to use mono_thread_create().

Another is to open the domain outside the threads with mono_jit_init(), then in the created threads call mono_thead_attach() at the beginning and mono_thread_detach() at the end.
Loading...