{
    "content": [
        {
            "type": "text",
            "text": "# threads::shared (perldoc)\n\n## NAME\n\nthreads::shared - Perl extension for sharing data structures between threads\n\n## SYNOPSIS\n\nuse threads;\nuse threads::shared;\nmy $var :shared;\nmy %hsh :shared;\nmy @ary :shared;\nmy ($scalar, @array, %hash);\nshare($scalar);\nshare(@array);\nshare(%hash);\n$var = $scalarvalue;\n$var = $sharedrefvalue;\n$var = sharedclone($nonsharedrefvalue);\n$var = sharedclone({'foo' => [qw/foo bar baz/]});\n$hsh{'foo'} = $scalarvalue;\n$hsh{'bar'} = $sharedrefvalue;\n$hsh{'baz'} = sharedclone($nonsharedrefvalue);\n$hsh{'quz'} = sharedclone([1..3]);\n$ary[0] = $scalarvalue;\n$ary[1] = $sharedrefvalue;\n$ary[2] = sharedclone($nonsharedrefvalue);\n$ary[3] = sharedclone([ {}, [] ]);\n{ lock(%hash); ...  }\ncondwait($scalar);\ncondtimedwait($scalar, time() + 30);\ncondbroadcast(@array);\ncondsignal(%hash);\nmy $lockvar :shared;\n# condition var != lock var\ncondwait($var, $lockvar);\ncondtimedwait($var, time()+30, $lockvar);\n\n## DESCRIPTION\n\nBy default, variables are private to each thread, and each newly created thread gets a private\ncopy of each existing variable. This module allows you to share variables across different\nthreads (and pseudo-forks on Win32). It is used together with the threads module.\n\n## Sections\n\n- **NAME**\n- **VERSION**\n- **SYNOPSIS**\n- **DESCRIPTION**\n- **EXPORT**\n- **FUNCTIONS**\n- **OBJECTS**\n- **NOTES**\n- **WARNINGS** (2 subsections)\n- **BUGS AND LIMITATIONS** (1 subsections)\n- **SEE ALSO**\n- **AUTHOR**\n- **LICENSE**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "threads::shared",
        "section": "",
        "mode": "perldoc",
        "summary": "threads::shared - Perl extension for sharing data structures between threads",
        "synopsis": "use threads;\nuse threads::shared;\nmy $var :shared;\nmy %hsh :shared;\nmy @ary :shared;\nmy ($scalar, @array, %hash);\nshare($scalar);\nshare(@array);\nshare(%hash);\n$var = $scalarvalue;\n$var = $sharedrefvalue;\n$var = sharedclone($nonsharedrefvalue);\n$var = sharedclone({'foo' => [qw/foo bar baz/]});\n$hsh{'foo'} = $scalarvalue;\n$hsh{'bar'} = $sharedrefvalue;\n$hsh{'baz'} = sharedclone($nonsharedrefvalue);\n$hsh{'quz'} = sharedclone([1..3]);\n$ary[0] = $scalarvalue;\n$ary[1] = $sharedrefvalue;\n$ary[2] = sharedclone($nonsharedrefvalue);\n$ary[3] = sharedclone([ {}, [] ]);\n{ lock(%hash); ...  }\ncondwait($scalar);\ncondtimedwait($scalar, time() + 30);\ncondbroadcast(@array);\ncondsignal(%hash);\nmy $lockvar :shared;\n# condition var != lock var\ncondwait($var, $lockvar);\ncondtimedwait($var, time()+30, $lockvar);",
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "VERSION",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "SYNOPSIS",
                "lines": 39,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "EXPORT",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "FUNCTIONS",
                "lines": 191,
                "subsections": []
            },
            {
                "name": "OBJECTS",
                "lines": 33,
                "subsections": []
            },
            {
                "name": "NOTES",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "WARNINGS",
                "lines": 1,
                "subsections": [
                    {
                        "name": "cond_broadcast",
                        "lines": 1
                    },
                    {
                        "name": "cond_signal",
                        "lines": 2
                    }
                ]
            },
            {
                "name": "BUGS AND LIMITATIONS",
                "lines": 69,
                "subsections": [
                    {
                        "name": "each",
                        "lines": 28
                    }
                ]
            },
            {
                "name": "SEE ALSO",
                "lines": 13,
                "subsections": []
            },
            {
                "name": "AUTHOR",
                "lines": 6,
                "subsections": []
            },
            {
                "name": "LICENSE",
                "lines": 2,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "threads::shared - Perl extension for sharing data structures between threads\n",
                "subsections": []
            },
            "VERSION": {
                "content": "This document describes threads::shared version 1.62\n",
                "subsections": []
            },
            "SYNOPSIS": {
                "content": "use threads;\nuse threads::shared;\n\nmy $var :shared;\nmy %hsh :shared;\nmy @ary :shared;\n\nmy ($scalar, @array, %hash);\nshare($scalar);\nshare(@array);\nshare(%hash);\n\n$var = $scalarvalue;\n$var = $sharedrefvalue;\n$var = sharedclone($nonsharedrefvalue);\n$var = sharedclone({'foo' => [qw/foo bar baz/]});\n\n$hsh{'foo'} = $scalarvalue;\n$hsh{'bar'} = $sharedrefvalue;\n$hsh{'baz'} = sharedclone($nonsharedrefvalue);\n$hsh{'quz'} = sharedclone([1..3]);\n\n$ary[0] = $scalarvalue;\n$ary[1] = $sharedrefvalue;\n$ary[2] = sharedclone($nonsharedrefvalue);\n$ary[3] = sharedclone([ {}, [] ]);\n\n{ lock(%hash); ...  }\n\ncondwait($scalar);\ncondtimedwait($scalar, time() + 30);\ncondbroadcast(@array);\ncondsignal(%hash);\n\nmy $lockvar :shared;\n# condition var != lock var\ncondwait($var, $lockvar);\ncondtimedwait($var, time()+30, $lockvar);\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "By default, variables are private to each thread, and each newly created thread gets a private\ncopy of each existing variable. This module allows you to share variables across different\nthreads (and pseudo-forks on Win32). It is used together with the threads module.\n\nThis module supports the sharing of the following data types only: scalars and scalar refs,\narrays and array refs, and hashes and hash refs.\n",
                "subsections": []
            },
            "EXPORT": {
                "content": "The following functions are exported by this module: \"share\", \"sharedclone\", \"isshared\",\n\"condwait\", \"condtimedwait\", \"condsignal\" and \"condbroadcast\"\n\nNote that if this module is imported when threads has not yet been loaded, then these functions\nall become no-ops. This makes it possible to write modules that will work in both threaded and\nnon-threaded environments.\n",
                "subsections": []
            },
            "FUNCTIONS": {
                "content": "share VARIABLE\n\"share\" takes a variable and marks it as shared:\n\nmy ($scalar, @array, %hash);\nshare($scalar);\nshare(@array);\nshare(%hash);\n\n\"share\" will return the shared rvalue, but always as a reference.\n\nVariables can also be marked as shared at compile time by using the \":shared\" attribute:\n\nmy ($var, %hash, @array) :shared;\n\nShared variables can only store scalars, refs of shared variables, or refs of shared data\n(discussed in next section):\n\nmy ($var, %hash, @array) :shared;\nmy $bork;\n\n# Storing scalars\n$var = 1;\n$hash{'foo'} = 'bar';\n$array[0] = 1.5;\n\n# Storing shared refs\n$var = \\%hash;\n$hash{'ary'} = \\@array;\n$array[1] = \\$var;\n\n# The following are errors:\n#   $var = \\$bork;                    # ref of non-shared variable\n#   $hash{'bork'} = [];               # non-shared array ref\n#   push(@array, { 'x' => 1 });       # non-shared hash ref\n\nsharedclone REF\n\"sharedclone\" takes a reference, and returns a shared version of its argument, performing a\ndeep copy on any non-shared elements. Any shared elements in the argument are used as is\n(i.e., they are not cloned).\n\nmy $cpy = sharedclone({'foo' => [qw/foo bar baz/]});\n\nObject status (i.e., the class an object is blessed into) is also cloned.\n\nmy $obj = {'foo' => [qw/foo bar baz/]};\nbless($obj, 'Foo');\nmy $cpy = sharedclone($obj);\nprint(ref($cpy), \"\\n\");         # Outputs 'Foo'\n\nFor cloning empty array or hash refs, the following may also be used:\n\n$var = &share([]);   # Same as $var = sharedclone([]);\n$var = &share({});   # Same as $var = sharedclone({});\n\nNot all Perl data types can be cloned (e.g., globs, code refs). By default, \"sharedclone\"\nwill croak if it encounters such items. To change this behaviour to a warning, then set the\nfollowing:\n\n$threads::shared::clonewarn = 1;\n\nIn this case, \"undef\" will be substituted for the item to be cloned. If set to zero:\n\n$threads::shared::clonewarn = 0;\n\nthen the \"undef\" substitution will be performed silently.\n\nisshared VARIABLE\n\"isshared\" checks if the specified variable is shared or not. If shared, returns the\nvariable's internal ID (similar to \"refaddr()\" (see Scalar::Util). Otherwise, returns\n\"undef\".\n\nif (isshared($var)) {\nprint(\"\\$var is shared\\n\");\n} else {\nprint(\"\\$var is not shared\\n\");\n}\n\nWhen used on an element of an array or hash, \"isshared\" checks if the specified element\nbelongs to a shared array or hash. (It does not check the contents of that element.)\n\nmy %hash :shared;\nif (isshared(%hash)) {\nprint(\"\\%hash is shared\\n\");\n}\n\n$hash{'elem'} = 1;\nif (isshared($hash{'elem'})) {\nprint(\"\\$hash{'elem'} is in a shared hash\\n\");\n}\n\nlock VARIABLE\n\"lock\" places a advisory lock on a variable until the lock goes out of scope. If the\nvariable is locked by another thread, the \"lock\" call will block until it's available.\nMultiple calls to \"lock\" by the same thread from within dynamically nested scopes are safe\n-- the variable will remain locked until the outermost lock on the variable goes out of\nscope.\n\n\"lock\" follows references exactly *one* level:\n\nmy %hash :shared;\nmy $ref = \\%hash;\nlock($ref);           # This is equivalent to lock(%hash)\n\nNote that you cannot explicitly unlock a variable; you can only wait for the lock to go out\nof scope. This is most easily accomplished by locking the variable inside a block.\n\nmy $var :shared;\n{\nlock($var);\n# $var is locked from here to the end of the block\n...\n}\n# $var is now unlocked\n\nAs locks are advisory, they do not prevent data access or modification by another thread\nthat does not itself attempt to obtain a lock on the variable.\n\nYou cannot lock the individual elements of a container variable:\n\nmy %hash :shared;\n$hash{'foo'} = 'bar';\n#lock($hash{'foo'});          # Error\nlock(%hash);                  # Works\n\nIf you need more fine-grained control over shared variable access, see Thread::Semaphore.\n\ncondwait VARIABLE\ncondwait CONDVAR, LOCKVAR\nThe \"condwait\" function takes a locked variable as a parameter, unlocks the variable, and\nblocks until another thread does a \"condsignal\" or \"condbroadcast\" for that same locked\nvariable. The variable that \"condwait\" blocked on is re-locked after the \"condwait\" is\nsatisfied. If there are multiple threads \"condwait\"ing on the same variable, all but one\nwill re-block waiting to reacquire the lock on the variable. (So if you're only using\n\"condwait\" for synchronization, give up the lock as soon as possible). The two actions of\nunlocking the variable and entering the blocked wait state are atomic, the two actions of\nexiting from the blocked wait state and re-locking the variable are not.\n\nIn its second form, \"condwait\" takes a shared, unlocked variable followed by a shared,\nlocked variable. The second variable is unlocked and thread execution suspended until\nanother thread signals the first variable.\n\nIt is important to note that the variable can be notified even if no thread \"condsignal\" or\n\"condbroadcast\" on the variable. It is therefore important to check the value of the\nvariable and go back to waiting if the requirement is not fulfilled. For example, to pause\nuntil a shared counter drops to zero:\n\n{ lock($counter); condwait($counter) until $counter == 0; }\n\ncondtimedwait VARIABLE, ABSTIMEOUT\ncondtimedwait CONDVAR, ABSTIMEOUT, LOCKVAR\nIn its two-argument form, \"condtimedwait\" takes a locked variable and an absolute timeout\nin *epoch* seconds (see time() in perlfunc for more) as parameters, unlocks the variable,\nand blocks until the timeout is reached or another thread signals the variable. A false\nvalue is returned if the timeout is reached, and a true value otherwise. In either case, the\nvariable is re-locked upon return.\n\nLike \"condwait\", this function may take a shared, locked variable as an additional\nparameter; in this case the first parameter is an unlocked condition variable protected by a\ndistinct lock variable.\n\nAgain like \"condwait\", waking up and reacquiring the lock are not atomic, and you should\nalways check your desired condition after this function returns. Since the timeout is an\nabsolute value, however, it does not have to be recalculated with each pass:\n\nlock($var);\nmy $abs = time() + 15;\nuntil ($ok = desiredcondition($var)) {\nlast if !condtimedwait($var, $abs);\n}\n# we got it if $ok, otherwise we timed out!\n\ncondsignal VARIABLE\nThe \"condsignal\" function takes a locked variable as a parameter and unblocks one thread\nthat's \"condwait\"ing on that variable. If more than one thread is blocked in a \"condwait\"\non that variable, only one (and which one is indeterminate) will be unblocked.\n\nIf there are no threads blocked in a \"condwait\" on the variable, the signal is discarded.\nBy always locking before signaling, you can (with care), avoid signaling before another\nthread has entered condwait().\n\n\"condsignal\" will normally generate a warning if you attempt to use it on an unlocked\nvariable. On the rare occasions where doing this may be sensible, you can suppress the\nwarning with:\n\n{ no warnings 'threads'; condsignal($foo); }\n\ncondbroadcast VARIABLE\nThe \"condbroadcast\" function works similarly to \"condsignal\". \"condbroadcast\", though,\nwill unblock all the threads that are blocked in a \"condwait\" on the locked variable,\nrather than only one.\n",
                "subsections": []
            },
            "OBJECTS": {
                "content": "threads::shared exports a version of bless() that works on shared objects such that *blessings*\npropagate across threads.\n\n# Create a shared 'Foo' object\nmy $foo :shared = sharedclone({});\nbless($foo, 'Foo');\n\n# Create a shared 'Bar' object\nmy $bar :shared = sharedclone({});\nbless($bar, 'Bar');\n\n# Put 'bar' inside 'foo'\n$foo->{'bar'} = $bar;\n\n# Rebless the objects via a thread\nthreads->create(sub {\n# Rebless the outer object\nbless($foo, 'Yin');\n\n# Cannot directly rebless the inner object\n#bless($foo->{'bar'}, 'Yang');\n\n# Retrieve and rebless the inner object\nmy $obj = $foo->{'bar'};\nbless($obj, 'Yang');\n$foo->{'bar'} = $obj;\n\n})->join();\n\nprint(ref($foo),          \"\\n\");    # Prints 'Yin'\nprint(ref($foo->{'bar'}), \"\\n\");    # Prints 'Yang'\nprint(ref($bar),          \"\\n\");    # Also prints 'Yang'\n",
                "subsections": []
            },
            "NOTES": {
                "content": "threads::shared is designed to disable itself silently if threads are not available. This allows\nyou to write modules and packages that can be used in both threaded and non-threaded\napplications.\n\nIf you want access to threads, you must \"use threads\" before you \"use threads::shared\". threads\nwill emit a warning if you use it after threads::shared.\n",
                "subsections": []
            },
            "WARNINGS": {
                "content": "",
                "subsections": [
                    {
                        "name": "cond_broadcast",
                        "content": ""
                    },
                    {
                        "name": "cond_signal",
                        "content": "See \"condsignal VARIABLE\", above.\n"
                    }
                ]
            },
            "BUGS AND LIMITATIONS": {
                "content": "When \"share\" is used on arrays, hashes, array refs or hash refs, any data they contain will be\nlost.\n\nmy @arr = qw(foo bar baz);\nshare(@arr);\n# @arr is now empty (i.e., == ());\n\n# Create a 'foo' object\nmy $foo = { 'data' => 99 };\nbless($foo, 'foo');\n\n# Share the object\nshare($foo);        # Contents are now wiped out\nprint(\"ERROR: \\$foo is empty\\n\")\nif (! exists($foo->{'data'}));\n\nTherefore, populate such variables after declaring them as shared. (Scalar and scalar refs are\nnot affected by this problem.)\n\nBlessing a shared item after it has been nested in another shared item does not propagate the\nblessing to the shared reference:\n\nmy $foo = &share({});\nmy $bar = &share({});\n$bar->{foo} = $foo;\nbless($foo, 'baz');   # $foo is now of class 'baz',\n# but $bar->{foo} is unblessed.\n\nTherefore, you should bless objects before sharing them.\n\nIt is often not wise to share an object unless the class itself has been written to support\nsharing. For example, a shared object's destructor may get called multiple times, once for each\nthread's scope exit, or may not get called at all if it is embedded inside another shared\nobject. Another issue is that the contents of hash-based objects will be lost due to the above\nmentioned limitation. See examples/class.pl (in the CPAN distribution of this module) for how to\ncreate a class that supports object sharing.\n\nDestructors may not be called on objects if those objects still exist at global destruction\ntime. If the destructors must be called, make sure there are no circular references and that\nnothing is referencing the objects before the program ends.\n\nDoes not support \"splice\" on arrays. Does not support explicitly changing array lengths via\n$#array -- use \"push\" and \"pop\" instead.\n\nTaking references to the elements of shared arrays and hashes does not autovivify the elements,\nand neither does slicing a shared array/hash over non-existent indices/keys autovivify the\nelements.\n\n\"share()\" allows you to \"share($hashref->{key})\" and \"share($arrayref->[idx])\" without giving\nany error message. But the \"$hashref->{key}\" or \"$arrayref->[idx]\" is not shared, causing the\nerror \"lock can only be used on shared values\" to occur when you attempt to\n\"lock($hashref->{key})\" or \"lock($arrayref->[idx])\" in another thread.\n\nUsing \"refaddr()\" is unreliable for testing whether or not two shared references are equivalent\n(e.g., when testing for circular references). Use isshared(), instead:\n\nuse threads;\nuse threads::shared;\nuse Scalar::Util qw(refaddr);\n\n# If ref is shared, use threads::shared's internal ID.\n# Otherwise, use refaddr().\nmy $addr1 = isshared($ref1) || refaddr($ref1);\nmy $addr2 = isshared($ref2) || refaddr($ref2);\n\nif ($addr1 == $addr2) {\n# The refs are equivalent\n}\n",
                "subsections": [
                    {
                        "name": "each",
                        "content": "my %foo :shared;\n$foo{'bar'} = sharedclone({'a'=>'x', 'b'=>'y', 'c'=>'z'});\n\nwhile (my ($key, $val) = each(%{$foo{'bar'}})) {\n...\n}\n\nEither of the following will work instead:\n\nmy $ref = $foo{'bar'};\nwhile (my ($key, $val) = each(%{$ref})) {\n...\n}\n\nforeach my $key (keys(%{$foo{'bar'}})) {\nmy $val = $foo{'bar'}{$key};\n...\n}\n\nThis module supports dual-valued variables created using \"dualvar()\" from Scalar::Util. However,\nwhile $! acts like a dualvar, it is implemented as a tied SV. To propagate its value, use the\nfollow construct, if needed:\n\nmy $errno :shared = dualvar($!,$!);\n\nView existing bug reports at, and submit any new bugs, problems, patches, etc. to:\n<http://rt.cpan.org/Public/Dist/Display.html?Name=threads-shared>\n"
                    }
                ]
            },
            "SEE ALSO": {
                "content": "threads::shared on MetaCPAN: <https://metacpan.org/release/threads-shared>\n\nCode repository for CPAN distribution: <https://github.com/Dual-Life/threads-shared>\n\nthreads, perlthrtut\n\n<http://www.perl.com/pub/a/2002/06/11/threads.html> and\n<http://www.perl.com/pub/a/2002/09/04/threads.html>\n\nPerl threads mailing list: <http://lists.perl.org/list/ithreads.html>\n\nSample code in the *examples* directory of this distribution on CPAN.\n",
                "subsections": []
            },
            "AUTHOR": {
                "content": "Artur Bergman <sky AT crucially DOT net>\n\nDocumentation borrowed from the old Thread.pm.\n\nCPAN version produced by Jerry D. Hedden <jdhedden AT cpan DOT org>.\n",
                "subsections": []
            },
            "LICENSE": {
                "content": "threads::shared is released under the same license as Perl.\n",
                "subsections": []
            }
        }
    }
}