Static Variables in C Blocks -- Don't?

As we all work through using C Blocks, I’ve seen mention of using static variables. I’m thinking that this is a bad idea generally. Here’s why (sorry for the lengthy explanation):

The C Block code is a component implemented in a DLL. We must assume that more than one instance of the component might be present in a higher-level schematic. However, there will be only one copy of the DLL running regardless of how many instances are present in the schematic. Static variables in the DLL are shared across all component instances. To work around this, Mike provides a “per-instance” structure pointer for each instance to allocate unique memory.

For those not familiar with DLLs, well, there must be a lot of “magic” under the QSpice hood. When a simulation is run, it must:

  • Load the DLL. This can fail if the DLL isn’t found.
  • If found, call DllMain() to let the DLL initialize itself. The DLL can return 0 if it cannot successfully initialize. (Example, the DLL might attempt to load other DLLs which cannot be found or fail to initialize properly for any other reason that it likes.)
  • Load handles for the various DLL methods/functions that QSpice knows about. The minimum would be the template-generated extern “C” __declspec(dllexport) void mod_name_lowercase(
    struct smod_name_original_case **opaque, double t, union uData *data) function. Others include the optional MaxExtStepSize() and Trunc() functions. Any and all of these might not exist in the component code and QSpice would call them only if it successfully loads the handles.
  • When the QSpice simulation ends, it calls Destroy() for each instance passing in the allocated memory per-instance memory handle. (Failure to free memory here will presumably cause memory leaks. The component code must also release any other resources allocated by the component.)

The point is, this DLL stuff is a bit more complicated than a casual programmer might realize.

[Now, I’ll suggest that some of this would be less confusing if the template-generator did NOT name the per-instance data structure with a module-derived name. It would make more sense to simply call it sPerInstanceData or similar.]

Anyway, if your component code needs to support multiple schematic instances with independent states, use the “per-instance” structure. Avoid static DLL variables.

As always, I could be wrong. Corrections welcome.

3 Likes

QSPICE brings .DLL writing and use to the masses. The .DLL allows an essentially unlimited amount of digital logic to be presented to your SPICE simulation. It is valuable. The .DLL ability of QSPICE is in response to the fact that simulation requirements have changed since SPICE was first announce 50 years ago.

The existing code templates address your concerns. It will offer to declare a blank struct so that each instance can have its own state variables no matter how many symbol instances call that .DLL.

The code template includes a destroy function, because some people’s sensibilities are such that everything malloc()'ed must be free()'ed. But that’s not true. The simulation is its own process and the structure is required as long as the process lives. Once the simulation is over, that process quits and all memory is released back to the OS whether you free()'ed it or not. Note free() doesn’t release memory to the OS, it only allows it to be reused for some other call to malloc by that process.

Not free()ing data that is needed up to the end of the process is not a leak.

–Mike

2 Likes

Thanks, Mike. FWIW, I was not criticizing the DLL functionality. I think it’s great.

Since you’re running each simulation in a separate process, leaky code won’t do more than starve the current simulation. Good to know.

Thanks for all of the excellent work!

– robert

1 Like