- Home /
functional multithreaded c++ code crashes if executed in Unity as native plugin
Edit: Solved. Accepted the answer because it was more useful for Unity users. However, as you may have suspected, it turns out I didn't sufficiently test my native code. In particular, after I wrote my own game module, I found a lot of chunks were being indexed inconsistently, leading to attempts to access pointers far beyond their bounds (I once accessed a chunk pointer with the world offset instead of the chunk offset, for example). There was another problem too: apparently, ERROR_ALREADY_EXISTS is different from ERROR_FILE_EXISTS so the chunk files were only being mapped if they didn't already exist.
Hi,
I have a set of routines in C++ that samples many megabytes of volumetric data from several memory-mapped files on-demand, i.e., whenever it needs to sample or modify a particular point it either generates it or loads it from a file-backed virtual memory. I expose two methods for this: GetVoxel() and SetVoxel(). Then I have another function StartWorld(), that creates a thread, which as long as the process is running updates an efficient curved bsp structure from all the voxel data, from a producer queue of chunks that need to be updated. I have a third function, Raycast(), that performs a software occlusion query or cone visibility approximation using a signed distance to the b-rep. I need to make a native plugin from them on Windows but they crash...only when invoked from Unity.
I have tested all of these in a simple C++11 console app and they work just fine, running all tests without issue on both Windows and Linux. The functions I expose to mono are extern "C" and I can verify it is running them from the dll with sane arguments. But when I try to run the plugin (call StartWorld(), then SetVoxel() a number of times, then RayCast() about 3200 times) in the editor it crashes the entire editor; a similar thing happens in the game build. I get an access violation somewhere trying to access my memory-mapped file. But here's the annoying thing: this is the exact sequence of calls I make in my C++ tests, which also use two threads and have no issues with concurrency, and my files are being created, and the pointers being returned by MapViewOfFile are valid (I logged the addresses, and it does indeed sample more than 16kb of voxel data before suddenly crashing).
What could be causing this disparity between how my code behaves in C++ and when invoked from mono in Unity?
I have this code in C#:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class VoxelWorldManager : MonoBehaviour {
[DllImport ("Fiefdom", EntryPoint = "GetVoxel", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetVoxel(int x, int y, int z);//this will create a new memory-mapped file view if the voxel coordinate doesn't exist. The corresponding c++ function is thread-safe.
[DllImport ("Fiefdom", EntryPoint = "SetVoxel", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetVoxel(int x, int y, int z, int voxel);//this will create a new memory-mapped file view if the voxel coordinate doesn't exist. The corresponding c++ function is thread-safe.
[DllImport("Fiefdom", EntryPoint = "LoadMap", CallingConvention = CallingConvention.Cdecl)]
public static extern void LoadMap([MarshalAs(UnmanagedType.LPStr)]string filename);//this simply passes the filename to the c++ code as a parameter. I know it works because files are being created with this name.
[DllImport ("Fiefdom", EntryPoint ="StartWorld", CallingConvention= CallingConvention.Cdecl)]
public static extern void StartWorld();//this spawns a new thread but in C++ when I use it it works.
[DllImport ("Fiefdom", EntryPoint = "Raycast", CallingConvention = CallingConvention.Cdecl)]
private static extern void Raycast([MarshalAs(UnmanagedType.LPArray, SizeConst = 5)] int[] voxel, float rx, float ry, float rz, float ex, float ey, float ez);//my code hasn't got as far as this yet from Unity but in C++ I can raycast as many times as I want, even while the chunks are being updated, critical sections protect from any synchronization issues.
}
Plus some start and update routines, etc... Start() calls the initialization routines then sets many voxels from a heightmap; Update() does a large number of very quick raycasts only after Start() has finished. The same sequence works when I do it in native code. }
Answer by Bunny83 · May 24, 2016 at 12:10 PM
Are you sure you use the right calling convention? The default calling convention (UNITY_INTERFACE_API inside the IUnityInterface.h
) for native plugins on windows is "stdcall" and not "cdecl". If you mess that up it will result in a crash as you mess up the stack that way. So make sure you use the correct one.
Apart from that are you sure that all your methods that are invoked from Unity are threadsafe? Concurrency problems are hard to debug and this is a typical symptom if it runs fine on one system but fails on another. If a racecondition causes a problem highly depends on the hardware / software combination and "random luck".
Another reason could be that you messed up the marshalling of the parameters. Do the method parameters use managed memory exclusively? We don't know how the interface of your DLL actually looks like.
Keep in mind that references to temporary managed variables passed to native code must not be stored on the native code side as the managed memory can't track the usage of the reference / pointer in native code. I'm thinking about the string parameter of "LoadMap" for example. You always should copy the data into some native memory if it should persist.
I understand that your library is quite complex and that you don't want / can't post the source here, but a bit more details about what happens with the parameters and how they are defined on the native side would help i guess.
Your answer
Follow this Question
Related Questions
UDP with coroutines crashing unity? 1 Answer
Editor crash "allocation 0x0xc000000000000000 already registered" 0 Answers
Crash on Application.Quit() in standalone mode after closing window 1 Answer
Invoking Windows Multimedia timer results to hang 1 Answer
How to synchronize native plugin texture update with orientation change from script 0 Answers