({{, (RefLink[SetSharedFunction, paclet:ref/SetSharedFunction])[(Subscript[f, 1]),(Subscript[f, 2]),…] 
declares the symbols (Subscript[f, i]) as shared functions whose downvalues are synchronized among all parallel kernels.}})

OpenersNotesSection(Spacer1)Details

Downvalues for a shared function defined on any kernel are maintained by the master kernel and every access on a parallel subkernel is synchronized through the master kernel.

Expressions of the form f[…] that would remain unevaluated give (RefLink[Null, paclet:ref/Null]).

OpenersPrimaryExamplesSection(Spacer1)Examples  (14)

OpenersExampleSection0(Spacer1)Basic Examples  (1)

Make fs be a (global) shared function:

SetSharedFunction[fs]

Each subkernel makes a definition for the same shared variable:

ParallelEvaluate[fs[$KernelID]=$ProcessID]

Definition[fs]

Without sharing, each subkernel has its own (local) copy of the function:

ParallelEvaluate[f[$KernelID]=$ProcessID]

Definition[f]

ParallelEvaluate[Print[Definition[f]]];

OpenersExampleSection1(Spacer1)Scope  (4)

Define and share a function:

next=1;
getnext[]:=next++
SetSharedFunction[getnext]

When called from each subkernel, the function updates next on the master kernel:

ParallelEvaluate[getnext[]]

Set up a shared function with a default rule:

nf[_]:=0
SetSharedFunction[nf]

Make additional definitions on the subkernels:

ParallelEvaluate[nf[$KernelID]=$ProcessID]

Since the function is shared, the master kernel knows about the additional rules:

Definition[nf]

Maintain indexed shared variables with a default value:

si[_]:=0;SetSharedFunction[si]

ParallelEvaluate[++si[$KernelID]]

Definition[si]

Define a shared function to manipulate the local variable results on the master kernel:

append[res_]:=(AppendTo[results,res];)
SetSharedFunction[append]

Call the function from the subkernels:

results={};
ParallelDo[If[PrimeQ[2^i+1],append[i]],{i,5000}]

The variable on the master has been modified:

results

OpenersExampleSection2(Spacer1)Generalizations & Extensions  (1)

A delayed definition for a shared function made on the master kernel:

SetSharedFunction[f1]

f1[n_]:=n*$KernelID

Such definitions are always evaluated on the master kernel, whichever kernel evaluates it:

ParallelMap[f1,Range[4]]

A definition for a shared function made on one of the parallel kernels:

SetSharedFunction[f2]

ParallelEvaluate[f2[n_]:=n*$KernelID,First[Kernels[]]]

Such definitions are always evaluated on the kernel that asks for the value:

ParallelMap[f2,Range[4]]

OpenersExampleSection4(Spacer1)Applications  (3)

Shared functions can be used for synchronization:

mlist={};
include[e_]:=(mlist=Union[mlist,{e}];)
SetSharedFunction[include]

ParallelDo[include[RandomInteger[10]],{10}]

mlist

Less efficient is the use of a shared variable and critical section:

slist={};SetSharedVariable[slist];
Clear[lock]

ParallelDo[e=RandomInteger[10];CriticalSection[{lock},slist=Union[slist,{e}]],{10}]

slist

A constructor for a simple queue data type:

newList[list_Symbol]:=Module[{data={}},
list[push,e_]:=(AppendTo[data,e];);
list[pop]:=If[Length[data]==0,$Failed,With[{e=First[data]},data=Rest[data];e]];
list[]:=data;
list]

Create two shared queues:

newList[input];SetSharedFunction[input]

newList[output];SetSharedFunction[output]

Fill the input queue:

Scan[input[push,#]&,Range[25,45]];input[]

Work on the elements of the input queue in parallel and put results into the output queue:

numberOfPrimes[n_]:=Total[FactorInteger[e!+1][[All,2]]];
DistributeDefinitions[numberOfPrimes]

ParallelEvaluate[While[(e=input[pop])=!=$Failed,output[push,{e,numberOfPrimes[e!+1]}]]];

output[]

Use a single shared function to communicate both input and result:

record[0,_]:=next++;
record[n_,nf_]:=(results[n]=nf;next++)
SetSharedFunction[record]

Set up a search and display its progress until it is manually aborted:

first=next=100;Clear[results];results[_]:="⌚";
PrintTemporary[Dynamic[{next,Array[results,next-first,first]}]];
CheckAbort[ParallelEvaluate[Module[{next=0,res},
While[True,next=record[next,res];res=Total[FactorInteger[2^next+1][[All,2]]]]
]],Null]

The results found so far—a list of the number of factors of (2^n)+1:

Style[Table[{n,results[n]},{n,first,next}],Small]

OpenersExampleSection5(Spacer1)Properties & Relations  (1)

Use a shared append function for a local variable to collect results:

append[res_]:=(AppendTo[localres,res];)
SetSharedFunction[append]

localres={};
ParallelDo[If[PrimeQ[2^i+1],append[i]],{i,1000}];
localres

Using (RefLink[AppendTo, paclet:ref/AppendTo]) on a shared variable has the same effect:

SetSharedVariable[sharedres]

sharedres={};
ParallelDo[If[PrimeQ[2^i+1],AppendTo[sharedres,i]],{i,1000}];
sharedres

OpenersExampleSection6(Spacer1)Possible Issues  (3)

A shared function is inefficient for mere code distribution and leads to sequential evaluation:

nfs[n_]:=Total[FactorInteger[2^n+1][[All,2]]];
SetSharedFunction[nfs]

AbsoluteTiming[ParallelMap[nfs,Range[140,160],Method->"FinestGrained"]]

Simply distribute the definitions of any function needed on the parallel kernels:

nfu[n_]:=Total[FactorInteger[2^n+1][[All,2]]];
DistributeDefinitions[nfu]

AbsoluteTiming[ParallelMap[nfu,Range[140,160],Method->"FinestGrained"]]

Separate read and write operations on a shared variable are not thread-safe:

ns=0;SetSharedVariable[ns]

ParallelEvaluate[ns=2ns+$KernelID]

ns

Use a shared function to synchronize access to an (unshared) variable:

nu=0;
update[kid_]:=(nu=2nu+kid);
SetSharedFunction[update]

ParallelEvaluate[update[$KernelID]]

nu

Alternatively, use (RefLink[CriticalSection, paclet:ref/CriticalSection]) to make a whole code section atomic:

ns=0;SetSharedVariable[ns];Clear[nlock]

ParallelEvaluate[CriticalSection[{nlock},ns=2ns+$KernelID]]

ns

Parallel dynamic programming:

SetSharedFunction[fib];
fib[1]=fib[2]=1;

ParallelEvaluate[fib[n_]:=fib[n]=fib[n-1]+fib[n-2],First[Kernels[]]]

ParallelTable[fib[i],{i,10}]

Definition[fib]

OpenersExampleSection7(Spacer1)Neat Examples  (1)

A parallel version of (RefLink[Sow, paclet:ref/Sow]):

sow[e_]:=Sow[e];
SetSharedFunction[sow]

Reap[ParallelDo[sow[$KernelID],{10}]]

({{DocumentationFooterIconsRelatedFunction.png, ({{See Also}, {(RefLink[$SharedFunctions, paclet:ref/$SharedFunctions])  ▪  (RefLink[UnsetShared, paclet:ref/UnsetShared])  ▪  (RefLink[SetSharedVariable, paclet:ref/SetSharedVariable])  ▪  (RefLink[DistributeDefinitions, paclet:ref/DistributeDefinitions])  ▪  (RefLink[DownValues, paclet:ref/DownValues])}})}})

({{DocumentationFooterIconsRelatedGuide.png, ({{Related Guides}, {▪(RefLinkPlain[Parallel Computing, paclet:guide/ParallelComputing])}, {▪(RefLinkPlain[Parallel Computation Setup & Configuration, paclet:guide/ParallelComputationSetupAndConfiguration])}, {▪(RefLinkPlain[Resource Sharing in Parallel Computing, paclet:guide/ResourceSharingInParallelComputing])}, {▪(RefLinkPlain[Concurrency, paclet:guide/Concurrency])}})}})