Wednesday, November 29, 2023
Home3D ModelingDoes CAPI assist multi-threading? - SketchUp SDK

Does CAPI assist multi-threading? – SketchUp SDK


When outputting Structure, I wish to generate mannequin viewports in a number of threads.

SDK_version: SDK_WIN_x64_2022-0-354
Supply Code: source_code.zip (2.1 KB)
Check file:test3.skp

I acquired exception from SketchupViewerAPI.dll

Unhandled exception at 0x00007FFFE69EBBF5(SketchUpViewerAPI.dll)(SketchUpTest.exe):There’s a battle when learn Handle 0xFFFFFFFFFFFFFFFF.

image

#embody<LayOutAPIlayout.h>
#embody<SketchUpAPIsketchup.h>
#embody<assert.h>
#embody<string>
#embody<cstdio>
#embody<vector>
#embody"threadpool.h"

#outline SU(api_function_call) {
  SUResult su_api_result = api_function_call;
  assert(SU_ERROR_NONE == su_api_result);
}

std::mutex _lockAddEntity;

int most important() {
	std::string skp_file = "F:/Desktop/relation_skp/test3.skp";

	LOInitialize();
	LODocumentRef doc = SU_INVALID;
	SU(LODocumentCreateEmpty(&doc));

	LOLayerRef layer = SU_INVALID;
	SU(LODocumentGetLayerAtIndex(doc, 0, &layer));

	LOPageRef web page = SU_INVALID;
	SU(LODocumentGetPageAtIndex(doc, 0, &web page));

	ThreadPool pool(4);

	std::vector<std::future<int>> executors;
	// test3.skp have 43 pages.  page1 - page43
	int num_of_out_page = 43; // It is okay when num_of_out_page=4.
	for (int i = 0; i < num_of_out_page; i++) {
		executors.emplace_back(pool.enqueue([&document, skp_file, i] {

			std::string page_name = "web page";
			char num_str[3] = { 0 };
			itoa(i + 1, num_str, 10);
			page_name.append(num_str);

			LOAxisAlignedRect2D rect;  // (0,0)  (5,5)
			rect.upper_left.x = rect.upper_left.y = 0;
			rect.lower_right.x = rect.lower_right.y = 5;
			LOSketchUpModelRef mannequin = SU_INVALID;

			SUResult res = LOSketchUpModelCreate(&mannequin, skp_file.c_str(), &rect);
			if (res == SU_ERROR_NONE) {
				std::unique_lock<std::mutex> lock{ _lockAddEntity };  // lock AddEntity

				res = LODocumentAddEntityUsingIndexes(doc, LOSketchUpModelToEntity(mannequin), 0, 0);
				if (res == SU_ERROR_NONE) {
					res = LOSketchUpModelSetCurrentScene(mannequin, i + 1);
					if (res == SU_ERROR_NONE)
						printf("%d %s okn", i, page_name.c_str());
					else
						printf("%d %s SetScene Error %dn", i, page_name.c_str(), res);
				}
				else
					printf("%d %s AddEntity Error %dn", i, page_name.c_str(), res);

				lock.unlock();  // unlock AddEntity

				SU(LOSketchUpModelRelease(&mannequin));  // launch SketchUpModel
			}
			else {
				printf("%d %s Create Error %dn", i, page_name.c_str(), res);
			}
			return i;
		}));
	}

	// most important thread wait all executor
	for (auto && executor : executors)
		executor.get();

	SU(LODocumentSaveToFile(doc, "F:/Desktop/relation_skp/check.structure", LODocumentVersion_Current));
	SU(LODocumentRelease(&doc));

	LOTerminate();
	printf("finishn");
	return 0;
}




1 Like

We can’t translate Chinese language from a picture. Please publish an English translation of the exception message.

Is skp_file the identical for all viewports ?

How would a number of threads be capable to learn from the identical file (or it’s illustration in reminiscence) and be capable to write to the identical reminiscence illustration of a LayOut doc, on the similar time ?


Additionally I don’t see that you simply’ve added the viewport to the LayOut doc inside the loop.
See: LODocumentAddEntity()

Typically, with the LayOut APIs, the entity must be first connected to a doc earlier than it’s properties might be modified. In any other case the entity’s properties get set to default values.

Unhandled exception at 0x00007FFFE69EBBF5(SketchUpViewerAPI.dll)(SketchUpTest.exe):There’s a battle when learn Handle 0xFFFFFFFFFFFFFFFF.
SketchUpTest is my program.

Sure, It’s similar file.

In my creativeness, multithreaded studying must be okay, as a result of it doesn’t contain writing.

If the identical file exists in SketchupViewAPI.dll, and the SKP file is parsed solely as soon as and there may be an operation to put in writing to reminiscence, the API might not be relevant to a number of threads.

You might be proper. My focus is on the LOSketchUpModelCreate.
And I need check it, as a result of the perform is time-consuming.

I replace.

What an fascinating query you might have requested. Whereas I doubt that the API was meant for use on this method, I discover that it’s attainable to create the LOSketchupModelRefs in parallel, drastically lowering the time wanted to provide the structure file. I totally count on somebody from SU to say it is a unhealthy concept!

The code beneath appears to work with ‘trendy’ Sketchup recordsdata whereas failing for older variations.

#embody<LayOutAPIlayout.h>
#embody <assert.h>
#embody<string>
#embody<cstdio>
#embody<vector>
#embody"threadpool.h"
//#embody <conio.h>

#outline SU(api_function_call) {
  SUResult su_api_result = api_function_call;
  assert(SU_ERROR_NONE == su_api_result);
}

int most important() {
	std::string skp_file = "C:/Customers/person/Desktop/test3.skp";

	LOInitialize();

	// Create a vector of LOSketchUpModelRefs utilizing a thread pool
	// 
	int num_of_out_page = 25;
	std::vector<LOSketchUpModelRef> fashions(num_of_out_page, SU_INVALID);

	ThreadPool pool(4);
	std::vector<std::future<int>> executors;

	for (int i = 0; i < num_of_out_page; i++) { 
		printf("Queueing: %dn", i);

		LOSketchUpModelRef*  mannequin = &fashions[i];
		executors.emplace_back(pool.enqueue([ model, skp_file,  i] {
			
			LOAxisAlignedRect2D rect;  // (0,0)  (5,5)
			rect.upper_left.x = rect.upper_left.y = 0.2;
			rect.lower_right.x = 10.8;
			rect.lower_right.y = 7.8;

			SUResult res = LOSketchUpModelCreate(mannequin, skp_file.c_str(), &rect);
			if (res == SU_ERROR_NONE) {
				printf("Created %dn", i);
			}
			else
			{
				printf("%d Create Error %dn", i, res);
			}
			return i;
			}));
	}

	// most important thread wait all executors
	for (auto&& executor : executors)
		executor.get();

	// It's informative to cease right here and take a look at the reminiscence use.
	// To take action, uncomment these strains and #embody <conio.h>
	// In Visible Studio open Debug>Home windows>Diagnostic Instruments
	// 
	//printf("The Fashions have been created. Press any key to proceed.");
	//int chr = _getch();
	//printf("n");

	// Add fashions to the Structure doc
	LODocumentRef doc = SU_INVALID;
	SU(LODocumentCreateEmpty(&doc));

	for (int i = 0; i < num_of_out_page; i++) {

		LOPageRef page_ref = SU_INVALID;
		if (i < 1)
			LODocumentGetPageAtIndex(doc, i, &page_ref);
		else
			LODocumentAddPage(doc, &page_ref);

		// Set the page_ref identify right here!!!

		SUResult res;
		res = LOSketchUpModelSetCurrentScene(fashions[i], i + (size_t)1);
		if (res == SU_ERROR_NONE)
		{
			//printf("Scene Set: %dn", i);
		}
		else
		{
			printf("SetScene Failed: %dn", i);
		}

		res = LODocumentAddEntityUsingIndexes(doc, LOSketchUpModelToEntity(fashions[i]), 0, i);
		if (res == SU_ERROR_NONE) 
		{
			printf("Added: %dn", i);
		}
		else
		{
			printf("Add Failed: %dn", i);
		}
	}

	SU(LODocumentSaveToFile(doc, "C:/Customers/person/Desktop/test3.structure", LODocumentVersion_Current));
	SU(LODocumentRelease(&doc));
	
	//for (int i = 0; i < num_of_out_page; i++) { SU(LOSketchUpModelRelease(&fashions[i])); }  // launch SketchUpModel

	LOTerminate();
	printf("Completedn");
	return 0;
}



1 Like

Thanks. It’s work. However I nonetheless wish to know why my writing will collapse.

LODocumentRef doc_ref = SU_INVALID;
LODocumentCreateEmpty(&doc_ref);
LORectangleRef rectangle_ref = SU_INVALID;
LOAxisAlignedRect2D rect_bounds = {{1.0, 2.0}, {4.0, 3.0}};
LORectangleCreate(&rectangle_ref, &rect_bounds);
// rectangle_ref now has a reference depend of 1.
LOEntityRef entity_ref = LORectangleToEntity(rectangle_ref);
LODocumentAddEntityUsingIndexes(doc_ref, entity_ref, 0 /* layer */, 0 /* web page */);
// The doc now holds a number of inside references to rectangle_ref, so
// its reference depend will probably be higher than 1.
LORectangleRelease(&rectangle_ref);
// rectangle_ref continues to be legitimate at this level, as a result of the doc nonetheless holds
// a number of references to it.
LODocumentRemoveEntity(doc_ref, &entity_ref);
// rectangle_ref is now invalid. Eradicating it from the doc brought on its
// reference depend to succeed in 0, so the article was deleted.
LODocumentRelease(&doc_ref);

And why not launch SketchUpModelView ?

I discover you tried to launch it.

Excessive effectivity is just too vital.

Typically, it isn’t protected for a number of threads to concurrently learn from and write to the identical file or reminiscence illustration of a LayOut doc with out correct synchronization. This will result in race situations, information corruption, and different errors.

To keep away from these points, synchronization mechanisms comparable to locks, semaphores, or different concurrency primitives must be used to coordinate entry to the shared useful resource. For instance, a mutex lock can be utilized to make sure that just one thread at a time can learn from or write to the file or reminiscence illustration. Alternatively, if the appliance is designed for high-concurrency situations, a extra superior synchronization mechanism comparable to a reader-writer lock or a concurrent information construction could also be used to permit a number of threads to concurrently learn from the identical useful resource whereas nonetheless guaranteeing information integrity.

It is very important notice that implementing concurrent file or reminiscence entry might be advanced and requires cautious design and testing to make sure correctness and efficiency. Moreover, the selection of synchronization mechanism will rely upon the particular necessities and traits of the appliance.



3 Likes

This matter has been mentioned previously …



2 Likes

Wow, all of that is manner above my fundamental understanding, but when I acquired the fundamentals of this, this sounds prefer it might dramatically enhance Structure’s updating references efficiency.

One work across the concern of a number of threads studying the identical information, is likely to be to first make momentary copies of the grasp SketchUp file into RAM so every thread will get it’s personal excessive velocity copy. I’ve a 64GB Ram system and all the time have loads of free RAM accessible. The subsequent different, is likely to be to make use of both a short lived location on the laborious drive (ideally a strong state laborious drive) or use the working techniques Pagefile mechanism.

Just a few non-expert ideas from a person that basically actually desires higher Structure efficiency badly.



1 Like

Okay, however we’re not discussing the LayOut utility right here. That is in regards to the C API that both runs inside a Third-party utility or runs inside SketchUp. Both manner, it’s a .structure file learn and write API solely.

The method is about to terminate and all the reminiscence will probably be launched when it does so. If this code is to be a part of a Ruby C Extension then you definitely’ll must launch the SketchUpModelView objects.

Again to why your preliminary try would fail. Did you discover that the method would seg_fault as quickly as a thread was reused? You probably did point out that queueing 4 requests labored simply effective in a pool of 4 threads however the fifth would crash. I’d picture that the SketchUpAPI is doing one thing akin to the Ruby OR EQUAL operator on the startup of a brand new name to LODocumentAddEntityUsingIndexes which, when the thread is reused, would fail to reinitialize the worth appropriately.

worth  ||= some_initial_value

In case you grow to be bold you may rewrite the threadpool to start out new threads as a substitute of reusing the outdated ones.

Additionally an enormous thanks to @DanRathbun for digging up the earlier dialogue of this matter.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments