Threads in Perl without using thread module

Threads are not good in Perl. If you want to know why, you can read PerlMonks article here. But C/C++ threads are good 🙂 How can you leverage the benefit of C/C++ threads in Perl? Well, if you have a C/C++ library which is multi-threaded then you can write a Perl wrapper on C/C++ library. For writing a wrapper you can use Inline::C or Inline::CPP module, that provides a very gentle and easy way to wrap up your C/C++ calls.

What happens is that if you call a C/C++ function which uses threads from a Perl script/process, it will make your Perl process multi-threaded. You can see this by using -m option of ps if you are on Linux platform.

I was working on a Perl based project and I used a multi-threaded C/C++ library. I was curious how will it work. I ran the Perl process and when I see the process in ps with -m option, it was showing two processes, actually one process and second was the thread. When I was using a single threaded library it used to show only a single process in ps. I also tested the functionality which was supposed to use the multiple threads and it worked as expected.

I think this is a better way to use threads in Perl if you really need threads, instead of using thread module of Perl. If you are not desperate, then try to stick with single threaded model of Perl, or use Perl wrapper over C/C++ multi-threaded library.

How to install MQSeries Perl Extension for IBM WebSphere MQ

I was having some issues installing MQSeries Perl Extension 1.29 for IBM WebSphere MQ (WMQ). What actually I did was downloaded the MQSeries module from the CPAN, extracted it and ran the perl Makefile.PL. But it gave me the following error:

> perl Makefile.PL
Checking if your kit is complete…
Looks good
ERROR from evaluation of /root/MQSeries-1.29/MQClient/Makefile.PL: No such directory ‘/opt/mqm’
Compilation failed in require at ./Makefile.PL line 14.
# Looks like your test died before it could output anything.

This seem as it needs /opt/mqm directory to install to and its not creating it by itself. But this was foolish assumption, as most applications create the required directories itself when installing, but still there wasn’t any clear error message. Then somehow I came to know about the client and I installed the MQSeriesClient. Installing MQSeriesClient requires MQSeriesRuntime as well. This created two directories:

  • /opt/mqm and
  • /var/mqm

So, that means Perl Extension was unable to find the client, but instead it was complaining about the directory. Well I moved forward and tried again installing MQSeries Perl Extension. But what? again error?

> perl Makefile.PL
Checking if your kit is complete…
Looks good
ERROR from evaluation of /home/jawaid/MQSeries-1.29/MQClient/Makefile.PL: Missing inc or include directory in /opt/mqm
Compilation failed in require at ./Makefile.PL line 14.
# Looks like your test died before it could output anything.

dahhh!! Now its complaining about another directory inc or include in /opt/mqm. That means it requires something else as well. The name of the directory i.e include, sparked in my mind that it might requires some kind of SDK or something. Then I checked the RPMs came with WMQ. I found MQSeriesSDK. hmmm so I thought lets try installing this RPM and try my luck again with installing Perl Extension. So I installed MQSeriesSDK and then MQSeries Perl Extension. woala!! this time it generated the make file without any errors 🙂

> perl Makefile.PL
Checking if your kit is complete…
Looks good
Writing Makefile for MQClient::MQSeries
Writing Makefile for MQSeries::Message::DeadLetter
Writing Makefile for MQSeries::Message::PCF
Warning: Guessing NAME [MQSeries-OAM] from current directory name.
No libmqm server library found, MQServer disabled
Support for MQServer is disabled on this platform.
Warning: Guessing NAME [MQServer] from current directory name.
Writing Makefile for MQSeries

But hold your breath for more. You can expect anything now after happening all this. Anyway, I ran make successfully then ran make test… what?? it failed??  :'(

aaahhh!! now what?? never mind!! I just ran make install… guess what? no, you are wrong 🙂 no errors this time, it got installed, even after failing the make test 🙂

To verify i tried to run the example perl script in examples directory of MQSeries Perl Extension to put message in the queue, and i got an error from the MQSeries library that it didn’t find the queue, obviously there were no queues at the moment, that means Perl module is installed correctly…whew!!

That means installing the run time and client are not enough. You need to install the WMQ SDK as well to install the MQSeries Perl Extension.

Since I wanted to play with the WebSphere MQ, so when I failed to install the Perl Extension first time, I decided to install the server first on another machine. Somehow I managed to install the server. Then I tried to install the MQSeries Perl Extension, but to no avail. Even after installing the Client. Then I moved to another machine and did the whole this thing from scratch, and at last it worked 🙂

Some coding tips!

This article highlights some common pitfalls that are being made by developers. I’ll elaborate it with a simple example.

$obj2->FuncOne( $obj1->GetData() );
$obj2->FuncTwo( $obj1->GetData() );

The result of GetData is passed to FuncOne and FuncTwo in two subsequent calls. What is the benefit of this approach? Simple answer is to save memory, by not using any variable to save the result. This argument was very strong until there were memories with very less capacity. But now even home user has a system with memory in GBs. So this practice is not good in today’s world.

So, what’s the drawback of this approach? Performance degradation. But how can it degrades the performance? Let me explain a bit. Consider a situation where GetData runs a query on database to fetch some data from multiple tables by joining them. Joins thereselves are heavy by nature. So when GetData is called twice it will run query twice, and suppose that this code snippet is a part of a heavy process that can be called by multiple users on the web or in an enterprise application, just imagine what will happen to the database and application itself. The performance of the application will be degraded. Users of your application will get frustrated and at the end you will lose business.

Now let’s look at it from another perspective. This approach will also increase the CPU workload. When GetData will be called it will jump from one branch instruction to another and before that it has to save the current address to the stack so it can pop it back when it returns back to the caller function. This has to be done every time when function is called. And when function performs heavy computation it needs more memory and processing power, increasing the footprint of your application and execution time. So you’re wasting your servant’s (CPU) time and energy by assigning it the same task twice.

Other drawbacks can be that code is more error prone and is difficult to debug and troubleshoot, and code maintenance is high, especially when you have to modify the code to meet new requirements.

You can make your application and code much better and efficient by adhering to few simple best practices. In this case the rule is that

“If result of a function is needed more than once then don’t call that function multiple times. Save the result of that function in a variable and use that variable instead. “

In view of this, above code could be written like this.

my $result = $obj1->GetData();
$obj2->FuncOne( $result );
$obj2->FuncTwo( $result );

There is one extra line of code in above example but is more efficient and is much more readable than the previous one.

Let’s see another example.

my $result = $obj1->GetData();
$result = { %$result, %$someData };
$obj2->FuncOne( $result );
$obj2->FuncTwo( $obj1->GetData() );

In this example developer fetches the result, appends another previously got data to it and passes it to FuncOne. Then he needs the same result, so he called GetData one more time. Now again, we can write this code in much efficient manner.

my $result = $obj1->GetData();
my $result2 = $result;

$result = { %$result, %$someData };

$obj2->FuncOne( $result );
$obj2->FuncTwo( $result2 );

Here we have saved another call to GetData, which might be performing some heavy computation or running a heavy query with joining multiple tables in it.