MainThread blocks all others

N

Nodir Gulyamov

Hello All!
I met some strange situation. In MainThread my program wating changes of
some variable. This variable should be changed in another thread, but loop,
which wait changing variable blocks all other threads.
Code below:

class class1:
def __init__(self):
self.counter = 0
result = doSomeJob()

def increaseCounter(self):
self.counter += 1

doSomeJob(self):
##### BLOCKING HERE ###
while counter != 1:
pass
# ... continue...

# this class subscribed to some observer which implements thread
class monitor:
def __init__(self, klass):
#do some init
self.c = klass
def update(self):
self.c.increaseCounter()

if __name__ == "__main__":
cl1 = class1()
m = monitor(cl1)
mo = MonitorObserver(m)


I am very confused how to resolve this problem. Any help will be
appreciated.

Thanks in advance to All.

Best regards,
/Gelios
 
B

Bryan Olson

Nodir said:
Hello All!
I met some strange situation. In MainThread my program wating changes of
some variable. This variable should be changed in another thread, but loop,
which wait changing variable blocks all other threads.
Code below:

class class1:
def __init__(self):
self.counter = 0
result = doSomeJob()

def increaseCounter(self):
self.counter += 1

doSomeJob(self):
##### BLOCKING HERE ###
while counter != 1:

Should that be self.counter?
pass
# ... continue...

# this class subscribed to some observer which implements thread
class monitor:
def __init__(self, klass):
#do some init
self.c = klass
def update(self):
self.c.increaseCounter()

if __name__ == "__main__":
cl1 = class1()
m = monitor(cl1)
mo = MonitorObserver(m)


I am very confused how to resolve this problem. Any help will be
appreciated.

Make self.counter a semaphore. Untested code:

import threading

class class1:
def __init__(self):
self.counter = threading.semaphore(0)
result = doSomeJob()

def increaseCounter(self):
self.counter.release()

doSomeJob(self):
# Busy-waiting sucks.
# while counter != 1:
# pass
self.counter.acquire()
# ... continue...
 
B

Bryan Olson

I said:
> Make self.counter a semaphore. Untested code:

A little clean-up. Still untested:

import threading

class class1:
def __init__(self):
self.counter = threading.semaphore(0)
result = self.doSomeJob()

def increaseCounter(self):
self.counter.release()

def doSomeJob(self):
# Busy-waiting sucks.
# while counter != 1:
# pass
self.counter.acquire()
# ... continue...
 
N

Nodir Gulyamov

Hi Bryan,
Thanks for your reply.
I tried to test your solution, but it doesn't work, hence
threading.Semaphore object hasn't method to get value of semaphore.
I looked to source code of semaphore.py and find out that value is private
variable.

Best regards,
/Gelios
 
N

Nodir Gulyamov

I had future investigation and as I understand in POSIX compliant threads,
getting value of semaphore should be exist.
As the matter of fact Python threads is not fully POSIX compliant. Pitty!
Contining looking for another solution.
 
N

Nodir Gulyamov

Tried to rewrite using Event() just as experiment, but unfortunately
MainThread will blocking all others.
Code below:

import threading

class class1:
def __init__(self):
self.myEvent = threading.Event()
result = doSomeJob()

def increaseCounter(self):
self.myEvent.set()

doSomeJob(self):
##### BLOCKING HERE ###
if not self.myEvent.isSet():
self.myEvent.wait()
self.myEvent.clear()
# ... continue...

# this class subscribed to some observer which implements thread
class monitor:
def __init__(self, klass):
#do some init
self.c = klass
def update(self):
self.c.increaseCounter()

if __name__ == "__main__":
cl1 = class1()
m = monitor(cl1)
mo = MonitorObserver(m)

Observer realized as described in Thinking in Python, Bruce Eckel
http://mindview.net/Books/TIPython

Does anybody have any idea? Any help will be appreciated.
Thanks in advance to ALL!

Best regards,
/Gelios
 
B

Bryan Olson

Nodir said:
> Hi Bryan,
> Thanks for your reply.
> I tried to test your solution, but it doesn't work, hence
> threading.Semaphore object hasn't method to get value of semaphore.
> I looked to source code of semaphore.py and find out that value is private
> variable.

Your code did not, and could not, use the value of counter for
anything but busy-waiting. You had:

while counter != 1:
pass
# ... continue...

If you replace this with the semaphore, you can just assume a
counter value of one.
 
B

Bryan Olson

Nodir said:
> Tried to rewrite using Event() just as experiment, but unfortunately
> MainThread will blocking all others.
> Code below:
>
> import threading
>
> class class1:
> def __init__(self):
> self.myEvent = threading.Event()
> result = doSomeJob()
>
> def increaseCounter(self):
> self.myEvent.set()
>
> doSomeJob(self):
> ##### BLOCKING HERE ###
> if not self.myEvent.isSet():
> self.myEvent.wait()

The initial 'if' is superflous.

> self.myEvent.clear()
> # ... continue...
>
> # this class subscribed to some observer which implements thread
> class monitor:
> def __init__(self, klass):
> #do some init
> self.c = klass
> def update(self):
> self.c.increaseCounter()
>
> if __name__ == "__main__":
> cl1 = class1()
> m = monitor(cl1)
> mo = MonitorObserver(m)

Obviously that won't work. You only have one thread, and it blocks
in doSomeJob, so no one can ever trigger the even.
 
N

Nodir Gulyamov

Hi,
Thanks your reply again. Please find my comments below.
Your code did not, and could not, use the value of counter for
anything but busy-waiting. You had:

while counter != 1:
pass
# ... continue...

If you replace this with the semaphore, you can just assume a
counter value of one.
I replaced it by semaphore, but how should i check is semaphore changed or
not?
When I call release() method of semaphore, internal counter is increased and
value will be equal to number of release() calls minus number of acquire()
calls. Am I right?
Ok, in this case what condition should I check in while statement?
 
N

Nodir Gulyamov

Hi again, comments below:
The initial 'if' is superflous.

Excuse me, please explain.
Obviously that won't work. You only have one thread, and it blocks
in doSomeJob, so no one can ever trigger the even.

Actually I have 2 threads. One of them is MainThread and second one is
created by Observer in which update method called.
 
B

Bryan Olson

Nodir said:
> Hi again, comments below:
>
>
>
> Excuse me, please explain.

The code:

if some_event.isSet():
some_event.wait()

does exactly the same thing as:

some_event.wait()

See:

http://docs.python.org/lib/event-objects.html

>
> Actually I have 2 threads. One of them is MainThread and second one is
> created by Observer in which update method called.

Whatever other thread you have in other code, this code is
whacked. Who do you think calls cl1.increaseCounter(), and how
did they get a reference to cl1?
 
D

Dennis Lee Bieber

Ok, in this case what condition should I check in while statement?
Typically, as I recall, a semaphore blocks when its value is 0.
You don't "check" if it is changed, you merely try to acquire it -- if
it is 0, the acquire blocks (without sucking up CPU time that your
while:pass loop does).

Though given that your original loop was a "!= 1", you could
only trigger on it ONCE unless you had code to decrement your counter
that we weren't seeing. You also never show us actual threads -- the
sample code you supplied is a linear, single path of execution.

From the original post
Code below:

class class1:
def __init__(self):
self.counter = 0
result = doSomeJob()

Actually, here is another possible problem... Maybe the REAL
problem -- See the **** below

Your INIT is calling doSomeJob, and will not return until that
finishes. But it won't finish until counter is = 1... And there is no
other way to increment it.
def increaseCounter(self):
self.counter += 1

doSomeJob(self):
##### BLOCKING HERE ###
while counter != 1:
pass
# ... continue...

# this class subscribed to some observer which implements thread
class monitor:
def __init__(self, klass):
#do some init
self.c = klass
def update(self):
self.c.increaseCounter()

if __name__ == "__main__":
cl1 = class1()
Create an instance of "class1" -- no threads here
*** Creating cl1 instance is invoking doSomeJob(), and doSomeJob is
waiting for counter to increment... Who can increment the counter since
this won't return until it does?
m = monitor(cl1)
Create an instance of "monitor" -- still no threads here
mo = MonitorObserver(m)
? We have no idea what this looks like... Does /it/ create a
thread for "m"

Now, backing up a bit... Does monitor.update() [m.update()] get
called more than once? As it is, you initialized class1.counter
[cl1.counter] to 0. class1.doSomeJob() is in a CPU hogging busy loop
waiting for counter to become 1. monitor.update() will increment the
counter, so class1.doSomeJob() will continue. Now, is that it? Does it
go on and exit? Does it come back to the top of class1.doSomeJob() (and
if it does, it will find class1.counter is STILL 1 and continue on again
-- unless it either decremented the counter somewhere so it is back to
0, or some other thread increments it again (and if it is incremented to
2, class1.doSomeJob() will never again get past your while:pass loop.


{How appropriate: Agent's spell checker is suggesting that "doSomeJob"
is supposed to really be "doom"}
--
 
N

Nodir Gulyamov

Hello Dennis and Bryan!
You were absolutely right. I should show you real code instead of brain
fucking. I am very sorry.
Please find below real code. Sorry for amount of sources.
Main aspect of program is all process should be in one determined sequence
containing 3 stages. They are defined as stage1(), stage2() and stage3() in
appMainFrame()
Execution started when Start button presses (handler def OnStart() in
appMainFrame() ). At the same time CardsObserver calls
appMainFrame.addCards() to increment counter and in each stages wait this
counter.
All other code from library.

Kind regards,
/Gelios

#######################Main application:################################

#exception class
class NotASIMCardException:
def __init__( self, message ):
self.message = message
def __str__(self):
return repr( self.message )


class SmartCardOperations:

def getATR( self, readerDescr ):
atr=""
self.attachedReaders = readers()
for reader in self.attachedReaders:
if readerDescr == str( reader ):
connection=reader.createConnection()
try:
connection.connect()
atr=toHexString( connection.getATR() )
connection.disconnect()
except NoCardException:
atr="no card inserted"
return atr

def decodeICCID( self, iccidBytes ):
resIccid = []

#swap bytes
i = 0
while i < len(iccidBytes):
strTmp = str( hex( iccidBytes ) )
if len(strTmp) == 3:
strTmp = strTmp[0] + strTmp[1] + "0" + strTmp[2]
resIccid += [strTmp[3] + strTmp[2]]
i += 1

#remove last 2 bytes
resIccid = resIccid[:-2]
#remove first last digit
strTmp = str( resIccid[i-3] )
if len(strTmp) == 1:
strTmp += "0"
resIccid[i-3] = strTmp[0]

return resIccid

def getICCID(self, readerDescr):
self.attachedReaders = readers()
for reader in self.attachedReaders:
if readerDescr == str( reader ):
session = smartcard.Session( reader )
try:
data, sw1, sw2 = session.sendCommandAPDU( SELECT +
DF_ROOT )
data, sw1, sw2 = session.sendCommandAPDU( SELECT +
EF_ICCID )
data, sw1, sw2 = session.sendCommandAPDU( READ_BINARY +
[0x0A])
if sw1 == 0x90 or sw1 == 0x91:
msg = "Ok"
else:
msg = "ICCID read error. Error code: " +
str(hex(sw1)) + str(hex(sw2))
session.close()
except NoCardException:
msg = "ICCID read error. Error code: " + str(hex(sw1)) +
str(hex(sw2))

return msg, self.decodeICCID(data), data

def getADM0( self, readerDescr, iccid ):
self.attachedReaders = readers()
for reader in self.attachedReaders:
if readerDescr == str( reader ):
session = smartcard.Session( reader )
try:
data, sw1, sw2 = session.sendCommandAPDU( SAM_SEND_ICCID
+ iccid )
resBytesStr = str(sw1) + ' ' + str(sw2)
if resBytesStr != "61 08":
msg = "?????? ?????? ? SAM ??????"
return msg, None
data, sw1, sw2 = session. sendCommandAPDU(
SAM_GET_ADM0 )
except NoCardException:
msg = "ADM0 getting error. Error code: " + str(hex(sw1))
+ str(hex(sw2))
msg = "Ok"
return msg, data

def chgEfLnd( self, iccid, adm0 ):
self.attachedReaders = readers()
for reader in self.attachedReaders:
if readerDescr == str( reader ):
session = smartcard.Session( reader )
try:
data, sw1, sw2 = session.sendCommandAPDU(
VERIFY_KEY_SIMERA3 + adm0 )
resBytesStr = str(sw1) + ' ' + str(sw2)
if resBytesStr == "98 04" or resBytesStr == "98 40":
msg = "?????? ??????? ? ?????"
return msg
data, sw1, sw2 = session.sendCommandAPDU( SELECT +
DF_ROOT )
data, sw1, sw2 = session.sendCommandAPDU( SELECT +
DF_GSM )
data, sw1, sw2 = session.sendCommandAPDU( DELETE_FILE )
if sw1 != 0x90 or sw1 != 0x91:
msg = "?????? ??????? ? ?????"
return msg
data, sw1, sw2 = session.sendCommandAPDU( SELECT +
DF_GSM )
data, sw1, sw2 = session.sendCommandAPDU(
smartcard.util.toBytes(CREATE_FILE_APDU)
if sw1 != 0x90 or sw1 != 0x91:
msg = "?????? ??????? ? ?????"
return msg
except NoCardException:
msg = "ADM0 getting error. Error code: " + str(hex(sw1))
+ str(hex(sw2))

msg = "Ok"
return msg


class appMainFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, -1, title, pos=(150,150),
size=(640,400), style = wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX |
wx.SYSTEM_MENU)

self.panel = wx.Panel(self)

# select reader controls
self.selectReaderTxt = wx.StaticText(self.panel, -1, "??????????
???????? reader: ", pos = (10, 12), size = (170, 21))
self.readerChoice = wx.Choice(self.panel, 120, pos = (180, 10), size
= (230,21), choices=['?? ??????'])
self.readerChoice.Select( 0 )
EVT_CHOICE( self, 120, self.selectReader)
self.cardDescr = wx.TextCtrl(self.panel, -1, "????? ?? ?????????",
pos = (415, 10), size = (205,21), style = wx.TE_READONLY )

self.staticLine2 = wx.StaticLine( self.panel, 210, pos = (10, 40),
size = (610, 2) )

#Log
self.logAreaTxt = wx.StaticText(self.panel, -1, "??????: ", pos =
(10, 50), size = (105, 21))
self.logArea = wx.TextCtrl( self.panel, 301, "", pos = (10, 72),
size = (610, 260), style=wx.TE_MULTILINE | wx.TE_READONLY )
self.saveLogButton = wx.Button( self.panel, -1, "?????? ??????? ?
????", pos = (20, 345) )
EVT_BUTTON( self, self.saveLogButton.GetId(), self.OnSaveLog )

#Buttons
self.resetButton = wx.Button( self.panel, -1, "?????", pos = (300,
345) )
self.startButton = wx.Button( self. panel, -1, "?????", pos = (380,
345) )
self.closeButton = wx.Button( self.panel, -1, "?????", pos = (460,
345) )
EVT_BUTTON( self, self.resetButton.GetId(), self.OnReset )
EVT_BUTTON( self, self.startButton.GetId(), self.OnStart )
EVT_BUTTON( self, self.closeButton.GetId(), self.OnClose )


# Set properties
self.SetTitle(title)

self.Layout()

#Smart card operations
self.scOps = SmartCardOperations()

self.START = False
self.step = None
self.cardEvent = threading.Event()

def selectReader(self, event):
self.selectedReader = event.GetString()
self.cardDescr.SetValue( self.scOps.getATR(self.selectedReader) )

def removeReaders( self, removedreaders ):
for readerToRemove in removedreaders:
self.readerChoice.Delete( self.readerChoice.FindString( str(
readerToRemove ) ) )

def addReaders( self, addedreaders ):
for readerToAdd in addedreaders:
self.readerChoice.Append( str ( readerToAdd ) )

def removeCards( self, removedcards ):
if self.readerChoice.GetSelection() != 0:
self.cardDescr.SetValue("????? ?? ?????????.")
else:
self.cardDescr.SetValue("?? ?????? reader.")

def addCards( self, cardsToAdd ):
if self.readerChoice.GetSelection() != 0:
self.cardDescr.SetValue(
self.scOps.getATR(self.selectedReader) )
if self.START == True:
rpdb2.settrace()
if self.step != None:
self.step.release()
#self.cardEvent.set()

def OnReset( self, event ):
if self.step != None:
self.step = None
self.START = False
self.logArea.AppendText("????? ????????. ??? ?????? ???????
?????\n")
event.Skip()

def OnClose( self, event ):
sys.exit()
event.Skip()

def OnStart( self, event ):
self.START = True
self.step = threading.Semaphore(0)
if self.step == 0:
#start process
#STAGE 1
self.logArea.AppendText( "1. ?????????? ???????? ??????????????
????? ? reader\n" )
iccid, plainIccid = self.stage1()

if iccid == None:
event.Skip()
return None
self.logArea.AppendText( "?????????? ?????? ??????????????
?????\n" )

#STAGE 2
self.logArea.AppendText( "2. ?????????? ???????? SAM ????? ?
reader\n" )
adm0 = self.stage2( plainIccid )
if adm0 == None:
event.Skip()
return None
self.logArea.AppendText( "?????????? ?????? SAM ?????\n" )

#STAGE 3
self.logArea.AppendText( "3. ?????????? ???????? ??????????????
????? ? reader\n" )
result = self.stage3(iccid, adm0)
if result == True:
self.logArea.AppendText( "????? ??????? ??????????\n" )
else:
self.logArea.AppendText( "?????? ????????? ?????.\n" )

else:
self.logArea.AppendText( "??????? ??? ???????? ? ????????????
??????????????????. ??????? ????? ? ??????? ??????\n" )

self.step = None
self.START = False

def stage1( self ):
#wait SIM card insertion
while self.step != 1:
pass
rpdb2.settrace()
###########################BLOCKING HERE##################################
if not self.cardEvent.isSet():
self.cardEvent.wait()
self.cardEvent.clear()

#check inserted card is a SIM card
msg, atr = self.scOps.getATR( self.selectedReader )
while atr == SAM_ATR:
self.logArea.AppendText( "??????????? ????? ???????? SAM ??????.
?????????? ???????? SIM ????? ? reader\n" )
########## Decrement semaphore value##############
self.step.acquire()
msg, atr = self.scOps.getATR( self.selectedReader )
if msg != "Ok":
self.logArea.AppendText( "?????? ?????? ?????. ??????? ?????
? ??????? ??????\n" )
return None, None

#read iccid of sim card
msg, iccid, plainIccid = self.scOps.getICCID( self.selectedReader )
if msg != "Ok":
self.logArea.AppendText( "?????? ?????? ?????. ??????? ????? ?
??????? ??????\n" )
return None, None

return iccid, plainIccid

def stage2( self, iccid ):
#wait SAM card insertion
while self.step != 2:
pass
#while not self.cardEvent.isSet():
# self.cardEvent.wait()
#self.cardEvent.clear()

#check is it SAM card
msg, atr = self.scOps.getATR( self.selectedReader )
while atr != SAM_ATR:
self.logArea.AppendText( "??????????? ????? ???????? ?? SAM
??????. ?????????? ???????? SAM ????? ? reader\n" )
########## Decrement semaphore value##############
self.step.acquire()
msg, atr = self.scOps.getATR( self.selectedReader )
if msg != "Ok":
self.logArea.AppendText( "?????? ?????? ?????. ??????? ?????
? ??????? ??????\n" )
return None

#get ADM0 key
msg, adm0 = self.scOps.getADM0( self.selectedReader, iccid )
if msg != "Ok":
self.logArea.AppendText( "?????? ?????? ? SAM ??????.
??????? ????? ? ??????? ??????\n" )
return None

return adm0

def stage3( self, old_iccid, adm0 ):
#wait SIM card insertion
while self.step != 3:
pass
#while not self.cardEvent.isSet():
# self.cardEvent.wait()

#self.cardEvent.clear()


#check ATR
msg, atr = self.scOps.getATR( self.selectedReader )
while atr == SAM_ATR:
self.logArea.AppendText( "??????????? ????? ???????? ?? SAM
??????. ?????????? ???????? SAM ????? ? reader\n" )
########## Decrement semaphore value##############
self.step.acquire()
msg, atr = self.scOps.getATR( self.selectedReader )
if msg != "Ok":
return False

#check iccid
msg, new_iccid, plain_new_iccid = self.scOps.getICCID(
self.selectedReader )

if msg != "Ok":
return False

while old_iccid != new_iccid:
if old_iccid != new_iccid:
self.logArea.AppendText( "? reader ????????? ????? ? ICCID="
+ str(new_iccid) + ". ????????? ??????? ????? ? ICCID=" + str(old_iccid))

msg = self.scOps.chgEfLnd(plain_new_iccid, adm0)
if msg != "Ok":
return False

return True

def OnSaveLog(self, event):
dlg = wx.FileDialog(self, "Choose a file", ".", "", "*.*", wx.OPEN)
try:
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
logfile = open(filename, 'w')
logfile.write(self.logArea.GetValue())
logfile.close()
finally:
dlg.Destroy()

def showMessage( self, message, title):
msgWin = wxMessageDialog ( None, message, title, wxOK )
msgWin.ShowModal()
msgWin.Destroy()


class ReadersObserver:
def __init__ ( self, frame ):
self.mainFrame = frame
def update( self, observable, ( addedreaders, removedreaders ) ):
self.mainFrame.removeReaders( removedreaders )
self.mainFrame.addReaders( addedreaders )

class CardsObserver:
def __init__( self, frame ):
self.mainFrame = frame
def update( self, observable, ( addedcards, removedcards ) ):
self.mainFrame.removeCards( removedcards )
self.mainFrame.addCards( addedcards )



class appChgLnd(wx.PySimpleApp):
def OnInit(self):
#create frame
self.appFrame = appMainFrame(None, "SimUpdate")
self.SetTopWindow( self.appFrame )

#create observer class instances
readersObserver = ReadersObserver( self.appFrame )
cardsObserver = CardsObserver( self.appFrame )

#subscribe to readers monitor and card monitor
self.cardsMonitor = CardMonitor()
self.cardsMonitor.addObserver( cardsObserver )
self.readersMonitor = ReaderMonitor()
self.readersMonitor.addObserver( readersObserver )

#show frame
self.appFrame.Show(True)
return True

if __name__ == '__main__':
try:
app = appChgLnd(0)
app.MainLoop()
except:
traceback.print_exc( file=open('errors.log', 'w'))




########################################## CARD
OBSERVER###################################
from sys import exc_info
from threading import Thread, Event
from time import sleep

from smartcard.System import readers
from smartcard.Exceptions import CardRequestTimeoutException
from smartcard.Observer import Observer
from smartcard.Observer import Observable

from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest

# CardObserver interface
class CardObserver(Observer):
"""
CardObserver is a base abstract class for objects that are to be
notified
upon smartcard reader insertion/removal.
"""
def __init__(self):
pass
def update( self, observable, (addedcards, removedcards) ):
"""Called upon reader insertion/removal.

observable:
addedcards: list of added readers causing notification
removedcards: list of removed readers causing notification
"""
pass

class CardMonitor:
"""Class that monitors smart card insertion/removal.
and notify observers

"""

class __CardMonitorSingleton( Observable ):
"""The real smartcard monitor class.

A single instance of this class is created
by the public CardMonitor class.
"""
def __init__(self):
Observable.__init__(self)
self.rmthread=None

def addObserver(self, observer):
"""Add an observer.

We only start the card monitoring thread when
there are observers.
"""
Observable.addObserver( self, observer )
if self.countObservers()>0 and self.rmthread==None:
self.rmthread = CardMonitoringThread( self )

def deleteObserver(self, observer):
"""Remove an observer.

We delete the CardMonitoringThread reference when there
are no more observers.
"""
Observable.deleteObserver( self, observer )
if self.countObservers()==0:
if self.rmthread!=None:
self.rmthread=None

# the singleton
instance = None

def __init__(self):
if not CardMonitor.instance:
CardMonitor.instance = CardMonitor.__CardMonitorSingleton()

def __getattr__(self, name):
return getattr(self.instance, name)


class CardMonitoringThread:
"""Card insertion thread.
This thread waits for card insertion.
"""

class __CardMonitoringThreadSingleton( Thread ):
"""The real card monitoring thread class.

A single instance of this class is created
by the public CardMonitoringThread class.
"""
def __init__(self, observable):
Thread.__init__(self)
self.observable=observable
self.stopEvent = Event()
self.stopEvent.clear()
self.cards = []
self.cardrequest = CardRequest( timeout=2 )
self.setDaemon(True)

# the actual monitoring thread
def run(self):
"""Runs until stopEvent is notified, and notify
observers of all card insertion/removal.
"""
while self.stopEvent.isSet()!=1:
try:
currentcards = self.cardrequest.waitforcardevent()

addedcards=[]
for card in currentcards:
if not self.cards.__contains__( card ):
addedcards.append( card )

removedcards=[]
for card in self.cards:
if not currentcards.__contains__( card ):
removedcards.append( card )

if addedcards!=[] or removedcards!=[]:
self.cards=currentcards
self.observable.setChanged()
self.observable.notifyObservers( (addedcards,
removedcards) )

except:
import sys
print sys.exc_info()[1]
print sys.exc_info()[2]
print sys.exc_info()[0]

# stop the thread by signaling stopEvent
def stop(self):
self.stopEvent.set()

# the singleton
instance = None

def __init__(self, observable):
if not CardMonitoringThread.instance:
CardMonitoringThread.instance =
CardMonitoringThread.__CardMonitoringThreadSingleton( observable )
CardMonitoringThread.instance.start()


def __getattr__(self, name):
return getattr(self.instance, name)

def __del__(self):
if CardMonitoringThread.instance!=None:
CardMonitoringThread.instance.stop()
CardMonitoringThread.instance = None


##################################### GENERAL
OBSERVER##############################
Class support for "observer" pattern.

The observer class is the base class
for all smartcard package observers.

"""

from smartcard.Synchronization import *

class Observer:
def update(observable, arg):
'''Called when the observed object is
modified. You call an Observable object's
notifyObservers method to notify all the
object's observers of the change.'''
pass

class Observable(Synchronization):
def __init__(self):
self.obs = []
self.changed = 0
Synchronization.__init__(self)

def addObserver(self, observer):
if observer not in self.obs:
self.obs.append(observer)

def deleteObserver(self, observer):
self.obs.remove(observer)

def notifyObservers(self, arg = None):
'''If 'changed' indicates that this object
has changed, notify all its observers, then
call clearChanged(). Each observer has its
update() called with two arguments: this
observable object and the generic 'arg'.'''

self.mutex.acquire()
try:
if not self.changed: return
# Make a local copy in case of synchronous
# additions of observers:
localArray = self.obs[:]
self.clearChanged()
finally:
self.mutex.release()
# Updating is not required to be synchronized:
for observer in localArray:
observer.update(self, arg)

def deleteObservers(self): self.obs = []
def setChanged(self): self.changed = 1
def clearChanged(self): self.changed = 0
def hasChanged(self): return self.changed
def countObservers(self): return len(self.obs)

synchronize(Observable,
"addObserver deleteObserver deleteObservers " +
"setChanged clearChanged hasChanged " +
"countObservers")
#:~


############################ SYNC######################

Simple emulation of Java's 'synchronized'
keyword, from Peter Norvig.
"""

from threading import RLock

def synchronized(method):
def f(*args):
self = args[0]
self.mutex.acquire();
# print method.__name__, 'acquired'
try:
return apply(method, args)
finally:
self.mutex.release();
# print method.__name__, 'released'
return f

def synchronize(klass, names=None):
"""Synchronize methods in the given class.
Only synchronize the methods whose names are
given, or all methods if names=None."""
if type(names)==type(''): names = names.split()
for (name, val) in klass.__dict__.items():
if callable(val) and name != '__init__' and \
(names == None or name in names):
# print "synchronizing", name
klass.__dict__[name] = synchronized(val)

# You can create your own self.mutex, or inherit
# from this class:
class Synchronization:
def __init__(self):
self.mutex = RLock()
#:~
 
D

Dennis Lee Bieber

I'm not going try to understand all the GUI stuff... Mostly I'm
going to just scroll through and insert a few comments -- stripping out
as much as I can for brevity...
#######################Main application:################################

#exception class
class NotASIMCardException:

Comment: Unless your python is really old, you might want to
inherit from exception... That is:

class NotASIMCardException(Exception):

It's just a suggestion...
def __init__( self, message ):
self.message = message

You might want to handle the situation of no "message" being
supplied...

def __init__(self, message="No details supplied"):
def __str__(self):
return repr( self.message )


class SmartCardOperations:

Comment: Along with the above comment about Exception, if you
want to use "new style" classes, inherit from object

class SmartCardOperations(object):

I didn't find any __init__() defined for this class. That might
be valid, though I've never seen it done that way -- usually one has
/some/ instance variables to be initialized.

class appMainFrame(wx.Frame):
def OnStart( self, event ):
self.START = True
self.step = threading.Semaphore(0)
if self.step == 0:

You don't test the value of a Semaphore, the idea of semaphores
is that you acquire it... If the internal counter has a value of 0, you
block until another thread does a .release (which increments the
semaphore internal counter -- your acquire will than decrement it, and
return "saying it is okay to process").
#start process
#STAGE 1
self.logArea.AppendText( "1. ?????????? ???????? ??????????????
????? ? reader\n" )
iccid, plainIccid = self.stage1()

This is a function call -- no threading is implied, and the
OnStart() event handler will not continue until .stage1() returns.
adm0 = self.stage2( plainIccid )

Same comment -- linear function call, no threading
result = self.stage3(iccid, adm0)

And for a third time...
def stage1( self ):
#wait SIM card insertion
while self.step != 1:
pass

Who is going to modify .step? You have no apparent threads, and
this is a polling loop that will suck up CPU time doing nothing. Hmmm,
looking ahead, you seem to be expecting .stage1, .stage2, and .stage3 to
all be running in parallel, spinning on a while loop whose condition
signals which of the three should exit the spin loop and do real
processing. If you really need to use such spin loops, at least put a
time.sleep() call inside so the processor doesn't just waste CPU cycles.

However, since all three are being called sequentially from
inside the OnStart event handler, there is no way for them to be in
parallel, and no need for the loops -- if you called .stage1() then you
must have wanted to run it, so why stop it with a CPU hog do-nothing
loop?

def stage2( self, iccid ):
#wait SAM card insertion
while self.step != 2:
pass

Another spin loop that can only work if you have another thread
that can change the value of .step
def stage3( self, old_iccid, adm0 ):
#wait SIM card insertion
while self.step != 3:
pass

And the third spin loop...
said:
class appChgLnd(wx.PySimpleApp):

Again, I don't see an __init__() in this class... Unless there
is some mysterious secret to the wx GUI system, you will have to
manually invoke .OnInit() (unless .MainLoop(), which I presume is
inherited from wx.PySimpleApp, calls .OnInit())
if __name__ == '__main__':
try:
app = appChgLnd(0)
app.MainLoop()

Comment: GUI mainloops tend to be event driven loops, not
"threads" in the formal sense.

Overall, I can't see how you expected those "stage" functions to
operate... You call them from a GUI event handler, which is sequential
logic (the GUI framework doesn't process any other events until the
event handler returns to the mainloop), and you call the stage stuff in
sequence.


except:
traceback.print_exc( file=open('errors.log', 'w'))




########################################## CARD
OBSERVER###################################
from sys import exc_info
from threading import Thread, Event
from time import sleep

from smartcard.System import readers
from smartcard.Exceptions import CardRequestTimeoutException
from smartcard.Observer import Observer
from smartcard.Observer import Observable

from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest

# CardObserver interface
class CardObserver(Observer):
"""
CardObserver is a base abstract class for objects that are to be
notified
upon smartcard reader insertion/removal.
"""
def __init__(self):
pass
def update( self, observable, (addedcards, removedcards) ):
"""Called upon reader insertion/removal.

observable:
addedcards: list of added readers causing notification
removedcards: list of removed readers causing notification
"""
pass

class CardMonitor:
"""Class that monitors smart card insertion/removal.
and notify observers

"""
said:
if self.countObservers()==0:
if self.rmthread!=None:
self.rmthread=None

Rather unsafe -- and ineffective I suspect. Setting
self.rmthread to None only wipes out the reference you had to the
thread... The thread OBJECT is still out there running UNLESS IT has a
test to exit when there are no observers... In that situation, you could
do a .join() to ensure you wait for it to clean-up.


said:
############################ SYNC######################

Simple emulation of Java's 'synchronized'
keyword, from Peter Norvig.
"""
Oh my... someone is trying to port Java coding style into
Python... <shudder>

--
 
N

Nodir Gulyamov

Dennis,
I am really appreciated you comments. Thanks you very much.
And let me a little bit explain idea of program. I should did it earlier.
Instead of empty loops i already tried to use time.sleep() firstly, but
effect was same, all other threads do not working too and as experiment i
tried empty loops then. All stages as numbered should be accomplished
sequently and no thread needed there. The reason of waiting in the begining
of each stage is waiting insertion of Sim cards to reader. When card
inserted CardMonitor which implements observer calls update() method of each
subscriber. In my case this is CardsObserver.update() method. This is
accomplished in seperate thread created in CardMonitor library class (by the
way I just only write main application, all other sources are from
framework). As you can see CardsObserver.update () calls
appMainFrame.addCards method which update step semaphore. I did realize it
by using semaphore based on Bryan solution. Firstly it was just only integer
variable and addCards() increment it by 1.
In any case I cannot understand why when MainThread is doing some action,
even sleeping (time.sleep()) all other threads blocked as well.
Regarding to other your comments. Honestly this is my first experience in
Python and as I suppose I didn't understand main principles and ideas of
Python up to now. Well, this is a way for future investigation. :)

Best regards,
/Gelios
 
D

Dennis Lee Bieber

And let me a little bit explain idea of program. I should did it earlier.
Instead of empty loops i already tried to use time.sleep() firstly, but
effect was same, all other threads do not working too and as experiment i
tried empty loops then. All stages as numbered should be accomplished
sequently and no thread needed there. The reason of waiting in the begining
of each stage is waiting insertion of Sim cards to reader. When card

From what I saw of the code, however, your stage1-3 are being
called from inside a GUI event handler. GUI event handlers are not
threads (in 99% of the GUI frameworks I've seen). If you are "waiting
for a card" INSIDE that event handler, the GUI will effectively freeze,
and ignore any other events.

Why is /each/ stage waiting for an "insert" event then? I'd
think you'd insert the card, and run all three on that one card.


I think I'm getting lost in too many "Java-isms"... Like you are
invoking a setChanged() only to immediately call a function whose first
test is "if changed"... Why? Drop the setChanged and the condition, and
just call the work function alone.

I'd probably separate the monitors from the GUI framework --
instead of making it a component of the framework.

Are you sure .waitforcardevent() is ever returning? (I'm going
to have to get ready to go to work soon...)

From what I can tell, as soon you click the "start" button, the
onStart event handler will do some short setup, and then (in the code
you posted yesterday)

if not self.cardEvent.isSet():
self.cardEvent.wait()
self.cardEvent.clear()

but the only cardEvent.set() call is commented out -- so the GUI onStart
handler will block at the above (and the if test is redundant; just do
the self.cardEvent.wait() -- if isSet would return true, wait() will
return immediately).

This will have the effect of freezing the GUI -- even if other
threads are running, the GUI won't show anything.


Overall, I think there is too much cross linking ... The GUI is
calling the monitor which is calling the observers which are calling the
GUI to do things, etc...

If I were starting over on this, I'd make the stage1-3 a
separate thread that waits for data to arrive on a Queue. onStart would
just signal the thread that it is safe to process. This would let the
GUI framework remain active.
--
 
B

Bryan Olson

Nodir said:
> [...]I should show you real code [...]
> Please find below real code. Sorry for amount of sources.

Yeah, it's too much for me. Can you construct a minimal
example that doesn't do what you think it should?
 
N

Nodir Gulyamov

Thank you very much to all. I found out solution. I created separate thread
from GUI and everything is working correct.

Best Regards,
/Gelios
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top