Perl Multithreading Comprehension

Source: Internet
Author: User
Tags exit in semaphore



Thread: A scan that uses multithreading to handle large amounts of data and encounters a possible deadlock in read-write files.




The life cycle of a Perl thread1. Use the Create () method of the Threads package:



use threads; 

sub say_hello { 
    printf("Hello thread! @_.\n"); 
    return( rand(10) ); 
} 

my $t1 = threads->create( \&say_hello, "param1", "param2" ); 
my $t2 = threads->create( "say_hello", "param3", "param4" ); 
my $t3 = threads->create( 
sub { 
    printf("Hello thread! @_\n"); 
    return( rand(10) ); 
}, "param5", "param6" );







2.join and Detach methods


once the thread is successfully created, it starts running immediately, and at this point you face two options, join or detach the new thread. Of course you can do nothing, but it's not a good habit,



in the literal sense, join is to combine the newly created thread into the current thread, treating it as part of the main thread and bringing them together. Join triggers two actions, first, the main thread requests the return value after the new thread execution finishes, and second, the new thread automatically releases its own system resources when it finishes executing and returns the result. For example



join reap new thread




#!/usr/bin/perl 
# 
use threads; 

sub func { 
 sleep(1); 
 return(rand(10)); 
} 

my $t1 = threads->create( \&func ); 
my $t2 = threads->create( \&func ); 

printf("do something in the main thread\n"); 

my $t1_res = $t1->join(); 
my $t2_res = $t2->join(); 

printf("t1_res = $t1_res\nt2_res = $t2_res\n");


It is easy to see that the timing of the call to join is a very interesting question. If the join method is called too early, and the new thread has not finished executing, nature cannot return any results, then the main thread will have to be blocked until the new thread has finished executing before the return value can be obtained, and the resource will be freed before the join can end. This largely breaks down the parallelism between threads. Conversely, if the join method is called too late, the new thread is already executed, and the resource it occupies has been unable to be released until it has been given a chance to return to the join, which wastes valuable system resources to a great extent. Therefore, the best time to join a new thread should be when it has just finished, so that it does not block the execution of the current thread, but also frees up the system resources that the new thread occupies.





foreach ( threads->list(threads::joinable) ){
        $_->join( );
}





Let's take a look at the detach method, which is perhaps the most hassle-------- In the literal sense, detach is to separate the newly created thread from the current thread, so that it is independent of the main thread. When you use the Detach method, it indicates that the main thread does not care about the results returned by the new threads, and Perl automatically frees the resources it consumes after the new thread finishes executing.



Detach Stripping Thread




#!/usr/bin/perl 
# 
use threads; 
use Config; 

sub say_hello { 
 my ( $name ) = @_; 
 printf("Hello World! I am $name.\n"); 
} 
my $t1 = threads->create( \&say_hello, "Alex" ); 
$t1->detach(); 
printf("doing something in main thread\n"); 
sleep(1);







once a new thread has been detach, it can no longer join. When you use the Detach method to peel off a thread, it's important to note that you need to make sure that the thread you create is finished before the thread ends, or that the line routines you create is forced to end, unless the result is exactly what you want, which may cause anomalies and increase the difficulty of debugging the program.


3. The demise of a thread





In most cases, you want the thread you create to exit normally, which means that the function body of the thread is returned and freed after the execution is complete. For example, in the example in Listing 5, the new thread exits the process after the join. However, if due to improper detach or because the main line due to some unexpected exception prematurely ended, although the thread it created may not have been completed, but they will still be forced to abort, is called with, Mao. At this point you may get a warning similar to "Perl exited with active threads".



Of course, you can also call the exit () method to end a thread, but it's worth noting that, by default, if you call the exit () method in one thread, the other threads will end up with it, and in many cases this may not be what you want if you want exit () Method only takes effect within the thread that invokes it, you need to set ' exit ' = ' thread_only ' When you create the thread. For example


Set the Exit property for a thread



#!/usr/bin/perl 
# 
use threads; 

sub say_hello { 
 printf("Hello thread! @_.\n"); 
 sleep(10); 
 printf("Bye\n"); 
} 

sub quick_exit { 
 printf("I will be exit in no time\n"); 
 exit(1); 
} 

my $t1 = threads->create( \&say_hello, "param1", "param2" ); 
my $t2 = threads->create( {‘exit‘=>‘thread_only‘}, \&quick_exit ); 

$t1->join(); 
$t2->join();







If you want each thread's exit method to work only on its own, then you should explicitly set the ' exit ' = ' thread_only ' property every time you create a new thread, and you can also introduce threads When the package is set this property is valid globally, for example



use threads (‘exit‘ => ‘threads_only‘); 

sub func { 
 ... 
 if( $condition ) { 
 exit(1); 
 } 
} 

my $t1 = threads->create( \&func ); 
my $t2 = threads->create( \&func ); 

$t1->join(); 
$t2->join();












Sharing and syncingThreads::shared
#!/usr/bin/perl 
 # 

 use threads; 
 use threads::shared; 
 use strict; 

 my $var   :shared  = 0;       # use :share tag to define 
 my @array :shared = (); # use :share tag to define 
 my %hash = (); 
 share(%hash);                  # use share() funtion to define 


 sub start { 
 $var = 100; 

 @array[0] = 200; 
 @array[1] = 201; 

 $hash{‘1‘} = 301; 
 $hash{‘2‘} = 302; 
 } 

 sub verify { 
    sleep(1);                      # make sure thread t1 execute firstly 
    printf("var = $var\n");     # var=100 

 for(my $i = 0; $i < scalar(@array); $i++) { 
        printf("array[$i] = $array[$i]\n");    # array[0]=200; array[1]=201 
 } 

 foreach my $key ( sort( keys(%hash) ) ) { 
 printf("hash{$key} = $hash{$key}\n"); # hash{1}=301; hash{2}=302 
 } 
 } 

 my $t1 = threads->create( \&start ); 
 my $t2 = threads->create( \&verify ); 

 $t1->join(); 
 $t2->join();


deadlock is often the most hidden problems in multi-threaded programs, often difficult to find and debug, but also increased the difficulty of troubleshooting problems. In order to avoid deadlock in the program, in the program we should try to avoid multiple shared variable lock, if unavoidable, then one is to try to use the same order to get multiple shared variable locks, as well as possible to refine the lock granularity, reduce the lock time.


use threads::shared; 

 # in thread 1 
 { 
    lock( $share );        # lock for 3 seconds 
    sleep(3);               # other threads can not lock again 
 } 
 # unlock implicitly now after the block 

 # in thread 2 
 { 
    lock($share);          # will be blocked, as already locked by thread 1 
    $share++;               # after thread 1 quit from the block 
 } 
 # unlock implicitly now after the block







use threads; 
 use threads::shared; 

 { 
    lock(@share);          # the array has been locked 
    lock(%hash);           # the hash has been locked 
    sleep(3);               # other threads can not lock again 
 } 

 { 
    lock($share[1]);     # error will occur 
    lock($hash{key});    # error will occur 
 }








Signal Volume: Thread::semaphore



My $semaphore = thread::semaphore->new ($max _threads); #信号量
My $mutex = thread::semaphore->new (1); #互斥量



Difference:



1. mutexes are used for mutual exclusion of threads, and semaphores are used for thread synchronization.



This is the fundamental difference between the mutex and the semaphore, which is the difference between the mutex and the synchronization.



Mutex: Refers to a resource that allows only one visitor to access it, with uniqueness and exclusion. However, mutual exclusion cannot limit the order in which visitors access resources, that is, access is unordered.



synchronization: Refers to the mutual exclusion of the basis (in most cases), through other mechanisms to achieve the visitor's orderly access to resources. In most cases, synchronization has been mutually exclusive, especially if all writes to the resource must be mutually exclusive. In rare cases, multiple visitors can be allowed to access resources at the same time



The above difference is the main want to remember.



Note: semaphores can be used to implement the function of mutex



2. The mutex value can only be 0/1, and the semaphore value may be a non-negative integer.



In other words, a mutex can only be used for mutually exclusive access to a resource, and it cannot implement multi-threaded mutex issues for multiple resources. The semaphore can realize multi-thread mutual exclusion and synchronization of multiple homogeneous resources. When the semaphore is a single-valued semaphore, it is also possible to complete a mutually exclusive access to a resource.



3. the lock and unlock of the mutex must be used by the same thread, the semaphore can be freed by one of the threads, and the other thread will get it.


use threads; 
use threads::shared; 
use Thread::Semaphore; 

my $s = Thread::Semaphore->new(); 
$s->down();                # P operation 
... 
$s->up();                  # V operation








Thread::queue: The producer-consumer model uses multithreaded queues.



producers can continue to do enqueue operations on the thread queue, and consumers simply need to do dequeue operations on the thread queue, which simply implements the problem of synchronization between producers and consumers.


#!/usr/bin/perl 
 # 

 use threads; 
 use Thread::Queue; 

 my $q = Thread::Queue->new(); 

 sub produce { 
    my $name = shift; 
    while(1) { 
        my $r = int(rand(100)); 
        $q->enqueue($r); 
        printf("$name produce $r\n"); 
        sleep(int(rand(3))); 
    } 
 } 

 sub consume { 
    my $name = shift; 
    while(my $r = $q->dequeue()) { 
        printf("consume $r\n"); 
    } 
 } 

 my $producer1 = threads->create(\&produce, "producer1"); 
 my $producer2 = threads->create(\&produce, "producer2"); 
 my $consumer1 = threads->create(\&consume, "consumer2"); 

 $producer1->join(); 
 $producer2->join(); 
 $consumer1->join();










Perl Multithreading Comprehension


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.