B
Bryan Balfour
I'm just picking up Perl and have been playing around with Thread and
have hit the buffers with my attempts to pass an object (workUnit)
between threads.
What seems to be happening is that the workUnit is successfully
enqueued in one thread and appears to be dequeued successfully in the
other thread. However the following failure message is output when an
attempt is made to extract data from this work unit:
Can't modify non-lvalue subroutine call at waitthread.pl line 71.
My questions are;
- what does the error message mean in the context of my code? Perl
knows that what was dequeued is an instance of my WorkUnit class (as it
says so in the output from line 42 below) so why can't I call its
methods?
- is the different HASH values in the enqueue and dequeue trying to
tell me something.
I'm guessing here, but I assume Perl defines an object in a hash. In
that case, the instance of WorkUnit class created in 'work thread'
below is defined in the hash at address 0x194fd60, right? (I assume
0x194fd60 is an address in memory). If this is true, where did the
WorkUnit instance at 0x1acea40 that was dequeued come from? Does Perl
create a copy? If so, it no longer points to the original WorkUnit.
- is my code faulty? (Quite likely)
- is my design faulty? Am I trying to do something that the Thread
package just doesn't support, or doesn't support on WindowsXP? (Like
passing objects between threads.)
- Have I hit a bug in the Thread package?
Relevant details follow:
I'm running Perl 5.8.6 under WindowsXP using the following classes:
Thread qw(async);
Thread::Queue;
Thread::Semaphore;
Win32::Event;
Basically, I have two threads, 'wait thread', which is created in the
main application, and 'work thread' which is created in the constructor
of my WorkThread class as follows:
19 my($className);
20 my($queueRef);
21 my($queueFlagRef);
22 my($queueEventRef);
23 my($workThread);
24 sub new
25 {
26 $className = shift(@_);
27 my($self) = {};
28 bless($self, $className);
29 $queueRef = shift(@_);
30 $queueFlagRef = shift(@_);
31 $queueEventRef = shift(@_);
32 $workThread = Thread->new(\&getWork);
33 $workThread->detach();
34 return($self);
35 }
I've another class called WorkUnit containing methods to set and get
'class' and 'data'.
In 'Work Thread' the following code:
111 $workUnit = WorkUnit->new();
112 $workUnit->setClass('X');
113 $workUnit->setData('Y');
114 lock $$queueFlagRef;
115 while(TRUE)
116 {
117 $$queueRef->enqueue($workUnit);
118 printMessage("Enqueued " . ref($workUnit) . " at
$workUnit...");
119 last;
120 }
121 $$queueEventRef->pulse();
produces the message:
08:38:56 WorkThread> Enqueued WorkUnit at
WorkUnit=HASH(0x194fd60)
at line 118.
In 'Wait Thread' the following code:
29 my $workQueue = new Thread::Queue;
30 my($workQueueFlag) = Thread::Semaphore->new(1);
31 my($workQueueEvent) = Win32::Event->new();
32 my($workThread) = WorkThread->new(\$WorkQueue, \$workQueueFlag,
\$workQueueEvent);
33 while(TRUE)
34 {
35 $workQueueEvent->wait();
36 while(TRUE)
37 {
38 lock $workQueueFlag;
39 while($workQueue->pending > 0)
40 {
41 $workUnit = $workQueue->dequeue_nb;
42 printMessage("Dequeued " . ref($workUnit) . " at
$workUnit...");
43 &processWorkUnit($workUnit);
44 }
45 last;
46 }
47 }
produces the message:
08:38:56 Wait Thread> Dequeued WorkUnit at
WorkUnit=HASH(0x1acea40)
at line 42.
In &processWorkUnit, the following code;
66 sub &processWorkUnit (\$)
67 {
68 my($workUnit) = @_;
69 while(TRUE)
70 {
71 if($workUnit->getClass() = 'X')
72 {
73 ......
74 last;
75 }
76 printMessage("Unknown work unit.");
77 last;
78 }
79 }
fails at line 71 with the message:
Can't modify non-lvalue subroutine call at waitthread.pl line 71.
Sorry about the long post.
Regards,
Bryan
have hit the buffers with my attempts to pass an object (workUnit)
between threads.
What seems to be happening is that the workUnit is successfully
enqueued in one thread and appears to be dequeued successfully in the
other thread. However the following failure message is output when an
attempt is made to extract data from this work unit:
Can't modify non-lvalue subroutine call at waitthread.pl line 71.
My questions are;
- what does the error message mean in the context of my code? Perl
knows that what was dequeued is an instance of my WorkUnit class (as it
says so in the output from line 42 below) so why can't I call its
methods?
- is the different HASH values in the enqueue and dequeue trying to
tell me something.
I'm guessing here, but I assume Perl defines an object in a hash. In
that case, the instance of WorkUnit class created in 'work thread'
below is defined in the hash at address 0x194fd60, right? (I assume
0x194fd60 is an address in memory). If this is true, where did the
WorkUnit instance at 0x1acea40 that was dequeued come from? Does Perl
create a copy? If so, it no longer points to the original WorkUnit.
- is my code faulty? (Quite likely)
- is my design faulty? Am I trying to do something that the Thread
package just doesn't support, or doesn't support on WindowsXP? (Like
passing objects between threads.)
- Have I hit a bug in the Thread package?
Relevant details follow:
I'm running Perl 5.8.6 under WindowsXP using the following classes:
Thread qw(async);
Thread::Queue;
Thread::Semaphore;
Win32::Event;
Basically, I have two threads, 'wait thread', which is created in the
main application, and 'work thread' which is created in the constructor
of my WorkThread class as follows:
19 my($className);
20 my($queueRef);
21 my($queueFlagRef);
22 my($queueEventRef);
23 my($workThread);
24 sub new
25 {
26 $className = shift(@_);
27 my($self) = {};
28 bless($self, $className);
29 $queueRef = shift(@_);
30 $queueFlagRef = shift(@_);
31 $queueEventRef = shift(@_);
32 $workThread = Thread->new(\&getWork);
33 $workThread->detach();
34 return($self);
35 }
I've another class called WorkUnit containing methods to set and get
'class' and 'data'.
In 'Work Thread' the following code:
111 $workUnit = WorkUnit->new();
112 $workUnit->setClass('X');
113 $workUnit->setData('Y');
114 lock $$queueFlagRef;
115 while(TRUE)
116 {
117 $$queueRef->enqueue($workUnit);
118 printMessage("Enqueued " . ref($workUnit) . " at
$workUnit...");
119 last;
120 }
121 $$queueEventRef->pulse();
produces the message:
08:38:56 WorkThread> Enqueued WorkUnit at
WorkUnit=HASH(0x194fd60)
at line 118.
In 'Wait Thread' the following code:
29 my $workQueue = new Thread::Queue;
30 my($workQueueFlag) = Thread::Semaphore->new(1);
31 my($workQueueEvent) = Win32::Event->new();
32 my($workThread) = WorkThread->new(\$WorkQueue, \$workQueueFlag,
\$workQueueEvent);
33 while(TRUE)
34 {
35 $workQueueEvent->wait();
36 while(TRUE)
37 {
38 lock $workQueueFlag;
39 while($workQueue->pending > 0)
40 {
41 $workUnit = $workQueue->dequeue_nb;
42 printMessage("Dequeued " . ref($workUnit) . " at
$workUnit...");
43 &processWorkUnit($workUnit);
44 }
45 last;
46 }
47 }
produces the message:
08:38:56 Wait Thread> Dequeued WorkUnit at
WorkUnit=HASH(0x1acea40)
at line 42.
In &processWorkUnit, the following code;
66 sub &processWorkUnit (\$)
67 {
68 my($workUnit) = @_;
69 while(TRUE)
70 {
71 if($workUnit->getClass() = 'X')
72 {
73 ......
74 last;
75 }
76 printMessage("Unknown work unit.");
77 last;
78 }
79 }
fails at line 71 with the message:
Can't modify non-lvalue subroutine call at waitthread.pl line 71.
Sorry about the long post.
Regards,
Bryan