[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [31417] branches/particles-2010: Fixed a multithreading bug that lead to freeze when using more than 2 threads .

Lukas Toenne lukas.toenne at googlemail.com
Tue Aug 17 15:28:12 CEST 2010


Revision: 31417
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=31417
Author:   lukastoenne
Date:     2010-08-17 15:28:12 +0200 (Tue, 17 Aug 2010)

Log Message:
-----------
Fixed a multithreading bug that lead to freeze when using more than 2 threads. This could happen because the operator stack could be depleted by 3 threads (in simple setups), while the others were still waiting for jobs and are never woken up. Keeping the mutex locked between ending a job a executing the next operator node and triggering the condition after that resolves the problem.

Modified Paths:
--------------
    branches/particles-2010/release/scripts/ui/properties_data_particleset.py
    branches/particles-2010/source/blender/blenkernel/intern/particleset.c
    branches/particles-2010/source/blender/makesdna/DNA_node_types.h
    branches/particles-2010/source/blender/makesrna/intern/rna_nodetree.c
    branches/particles-2010/source/blender/nodes/intern/node_tree_simulation.c

Modified: branches/particles-2010/release/scripts/ui/properties_data_particleset.py
===================================================================
--- branches/particles-2010/release/scripts/ui/properties_data_particleset.py	2010-08-17 13:14:41 UTC (rev 31416)
+++ branches/particles-2010/release/scripts/ui/properties_data_particleset.py	2010-08-17 13:28:12 UTC (rev 31417)
@@ -21,7 +21,7 @@
 from rna_prop_ui import PropertyPanel
 
 
-class DataButtonsPanel(bpy.types.Panel):
+class DataButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
     bl_context = "data"
@@ -31,7 +31,7 @@
         return context.particleset
 
 
-class DATA_PT_context_particleset(DataButtonsPanel):
+class DATA_PT_context_particleset(DataButtonsPanel, bpy.types.Panel):
     bl_label = ""
     bl_show_header = False
 
@@ -48,11 +48,11 @@
             layout.template_ID(space, "pin_id")
 
 
-class DATA_PT_custom_props_particleset(DataButtonsPanel, PropertyPanel):
+class DATA_PT_custom_props_particleset(DataButtonsPanel, PropertyPanel, bpy.types.Panel):
     _context_path = "object.data"
 
 
-class DATA_PT_particleset(DataButtonsPanel):
+class DATA_PT_particleset(DataButtonsPanel, bpy.types.Panel):
     bl_label = "Particle Set"
 
     def draw(self, context):
@@ -85,23 +85,11 @@
             col.prop(pp, "offset")
 
 
-classes = [
-    DATA_PT_context_particleset,
-    DATA_PT_particleset,
-
-    DATA_PT_custom_props_particleset]
-
-
 def register():
-    register = bpy.types.register
-    for cls in classes:
-        register(cls)
+    pass
 
-
 def unregister():
-    unregister = bpy.types.unregister
-    for cls in classes:
-        unregister(cls)
+    pass
 
 if __name__ == "__main__":
     register()

Modified: branches/particles-2010/source/blender/blenkernel/intern/particleset.c
===================================================================
--- branches/particles-2010/source/blender/blenkernel/intern/particleset.c	2010-08-17 13:14:41 UTC (rev 31416)
+++ branches/particles-2010/source/blender/blenkernel/intern/particleset.c	2010-08-17 13:28:12 UTC (rev 31417)
@@ -751,6 +751,9 @@
 	
 	pset_add_default_properties(pset);
 	
+	/* add a nodetree modifier by default */
+	/* TODO */
+	
 	return pset;
 }
 

Modified: branches/particles-2010/source/blender/makesdna/DNA_node_types.h
===================================================================
--- branches/particles-2010/source/blender/makesdna/DNA_node_types.h	2010-08-17 13:14:41 UTC (rev 31416)
+++ branches/particles-2010/source/blender/makesdna/DNA_node_types.h	2010-08-17 13:28:12 UTC (rev 31417)
@@ -120,6 +120,7 @@
 #define SOCK_BOOL		5
 #define SOCK_INT		6
 #define SOCK_FLOAT		7
+#define SOCK_STRING		8
 
 /* sock->flag, first bit is select */
 	/* hidden is user defined, to hide unused */

Modified: branches/particles-2010/source/blender/makesrna/intern/rna_nodetree.c
===================================================================
--- branches/particles-2010/source/blender/makesrna/intern/rna_nodetree.c	2010-08-17 13:14:41 UTC (rev 31416)
+++ branches/particles-2010/source/blender/makesrna/intern/rna_nodetree.c	2010-08-17 13:28:12 UTC (rev 31417)
@@ -99,6 +99,8 @@
 			return &RNA_FloatNodeSocket;
 		case SOCK_BOOL:
 			return &RNA_BoolNodeSocket;
+		case SOCK_STRING:
+			return &RNA_StringNodeSocket;
 		default:
 			return &RNA_UnknownType;
 	}
@@ -2351,6 +2353,28 @@
 	RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_NodeSocket_update");
 }
 
+static void rna_def_node_socket_string(BlenderRNA *brna)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+	
+	srna = RNA_def_struct(brna, "StringNodeSocket", NULL);
+	RNA_def_struct_ui_text(srna, "String Node Socket", "Input or output socket of a node");
+	RNA_def_struct_sdna(srna, "bNodeSocket");
+	RNA_def_struct_ui_icon(srna, ICON_PLUG);
+	RNA_def_struct_path_func(srna, "rna_NodeSocket_path");
+	
+	prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+	RNA_def_property_ui_text(prop, "Name", "Socket name");
+	RNA_def_struct_name_property(srna, prop);
+	
+	prop = RNA_def_property(srna, "default_value", PROP_STRING, PROP_NONE);
+	RNA_def_property_string_sdna(prop, NULL, "ns.data");
+	RNA_def_property_ui_text(prop, "Default Value", "Default value of the socket when no link is attached");
+	RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_NodeSocket_update");
+}
+
 static void rna_def_node(BlenderRNA *brna)
 {
 	StructRNA *srna;
@@ -2434,6 +2458,7 @@
 	rna_def_node_socket_int(brna);
 	rna_def_node_socket_float(brna);
 	rna_def_node_socket_bool(brna);
+	rna_def_node_socket_string(brna);
 	rna_def_node(brna);
 	rna_def_shader_node(brna);
 	rna_def_compositor_node(brna);

Modified: branches/particles-2010/source/blender/nodes/intern/node_tree_simulation.c
===================================================================
--- branches/particles-2010/source/blender/nodes/intern/node_tree_simulation.c	2010-08-17 13:14:41 UTC (rev 31416)
+++ branches/particles-2010/source/blender/nodes/intern/node_tree_simulation.c	2010-08-17 13:28:12 UTC (rev 31417)
@@ -367,15 +367,13 @@
 	return hasnewjobs;
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static SimNodeJob *node_thread_find_job(SimNodeThreadContext *ctx)
 {
 	SimNodeJob *job=NULL;
 	SimNodeInstance *node;
 	int n;
 	
-	/* TODO it might be beneficial to use RW lock here or even per-node mutexes if searching for jobs takes significant time */
-	pthread_mutex_lock(&ctx->mutex);
-	
 	while (1) {
 		#if 0
 		{
@@ -509,14 +507,13 @@
 		else
 			break;
 	}
-	pthread_mutex_unlock(&ctx->mutex);
 	
 	return job;
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static void node_thread_suspend_job(SimNodeThreadContext *ctx, SimNodeJob *job)
 {
-	pthread_mutex_lock(&ctx->mutex);
 	if (job->state == SIM_JOB_RUNNING) {
 		job->state = SIM_JOB_SUSPENDED;
 		++job->execlevel;
@@ -541,12 +538,11 @@
 		if (ctx->active <= 0)
 			pthread_cond_signal(&ctx->cond);
 	}
-	pthread_mutex_unlock(&ctx->mutex);
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static void node_thread_finish_job(SimNodeThreadContext *ctx, SimNodeJob *job)
 {
-	pthread_mutex_lock(&ctx->mutex);
 	if (job->state == SIM_JOB_RUNNING || job->state == SIM_JOB_CANCEL) {
 		job->state = SIM_JOB_DONE;
 		if (job->node->node->typeinfo->sim_endjobfunc)
@@ -562,12 +558,11 @@
 		if (ctx->active <= 0)
 			pthread_cond_signal(&ctx->cond);
 	}
-	pthread_mutex_unlock(&ctx->mutex);
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static void node_thread_cancel_job(SimNodeThreadContext *ctx, SimNodeJob *job)
 {
-	pthread_mutex_lock(&ctx->mutex);
 	if (job->state == SIM_JOB_RUNNING) {
 		job->state = SIM_JOB_CANCEL;
 	}
@@ -583,16 +578,15 @@
 		
 		/* TODO decrease branch counters and free data if possible */
 	}
-	pthread_mutex_unlock(&ctx->mutex);
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static void node_thread_cancel_all_jobs(SimNodeThreadContext *ctx)
 {
 	SimNodeInstance *node;
 	SimNodeJob *job;
 	int n;
 
-	pthread_mutex_lock(&ctx->mutex);
 	for (n=0, node=ctx->nodestack; n < ctx->totnode; ++n, ++node) {
 		for (job=node->jobs.first; job; job=job->next) {
 			if (job->state == SIM_JOB_RUNNING) {
@@ -612,7 +606,6 @@
 			}
 		}
 	}
-	pthread_mutex_unlock(&ctx->mutex);
 }
 
 int sim_insert_output_batch(SimNodeThreadContext *ctx, SimNodeInstance *node, SimNodeSocketInstance *sock, SimNodeBatch *batch)
@@ -734,6 +727,7 @@
 	}
 }
 
+/* Not threadsafe! ctx->mutex must be locked during this function! */
 static int node_thread_exec_op(SimNodeThreadContext *ctx)
 {
 //	bNodeTree *ntree= ctx->sim->ntmd->nodetree;
@@ -741,8 +735,6 @@
 	SimNodeOperator *cur_op, *next_op;
 	int opsock, suspend;
 
-	pthread_mutex_lock(&ctx->mutex);
-	
 	cur_op = (SimNodeOperator*)ctx->opstack.last;
 	if (cur_op) {
 		/* execute operator and update execution stack */
@@ -776,8 +768,6 @@
 		cur_op = (SimNodeOperator*)ctx->opstack.last;
 	}
 	
-	pthread_mutex_unlock(&ctx->mutex);
-	
 	return (cur_op != 0);
 }
 
@@ -794,9 +784,10 @@
 		 * access the next/prev pointers or the state (which are modified when other jobs are added/removed).
 		 * These need locking of the context mutex first. Could be made more fool-proof later.
 		 */
-//		printf("Thread %d/%d searching job:\n", thread->num, ctx->totthread);
+		pthread_mutex_lock(&ctx->mutex);
 		job = node_thread_find_job(ctx);
 		if (job != NULL) {
+			pthread_mutex_unlock(&ctx->mutex);	/* unlock mutex during job execution */
 			#if 0
 			/* ========= DEBUG ========= */
 			{
@@ -875,13 +866,19 @@
 			/* ========================= */
 			#endif
 
+			pthread_mutex_lock(&ctx->mutex);
 			if (suspend == NODE_EXEC_SUSPEND)
 				node_thread_suspend_job(ctx, job);
 			else
 				node_thread_finish_job(ctx, job);
+			pthread_mutex_unlock(&ctx->mutex);
 		}
 		else {
-			if (!node_thread_exec_op(ctx))
+			int has_op;
+			has_op = node_thread_exec_op(ctx);
+			pthread_cond_signal(&ctx->cond);	/* wake threads to look for new jobs or exit */
+			pthread_mutex_unlock(&ctx->mutex);
+			if (!has_op)
 				break;
 		}
 	}





More information about the Bf-blender-cvs mailing list