i've been trying track down memory leak in jedi vcl's jvhidcontrollerclass.pas, came across change in source history:
older revision:
constructor tjvhiddevicereadthread.ctlcreate(const dev: tjvhiddevice); begin inherited create(true); device := dev; numbytesread := 0; setlength(report, dev.caps.inputreportbytelength); end; current revision:
constructor tjvhiddevicereadthread.ctlcreate(const dev: tjvhiddevice); begin inherited create(false); device := dev; numbytesread := 0; setlength(report, dev.caps.inputreportbytelength); end; from experience, i've discovered if create thread not suspended:
inherited create(false); then thread starts running. in case attempt access object has not been initialized yet:
procedure tjvhiddevicereadthread.execute; begin while not terminated begin fillchar(report[0], device.caps.inputreportbytelength, #0); if device.readfileex(report[0], device.caps.inputreportbytelength, @dummyreadcompletion) right away trying fill report, , access object device. problem haven't been initialized yet; next lines after thread has started:
device := dev; numbytesread := 0; setlength(report, dev.caps.inputreportbytelength); i realize race condition; , chances of user experiencing crash in production pretty low, it's harmless leave race-crash.
but way off? missing something? calling:
beginthread(nil, 0, @threadproc, pointer(self), flags, fthreadid); not start thread off , running right away? race condition regression (intentionally) added jvcl? there secret
createsuspended(false); that makes correct code over:
createsuspended(true); ... fdatathread.resume; ?
after having been burned mistakenly calling
tmythread.create(false) i've filed in brain never correct. there valid use letting thread start right away (when have initialize values)?
this basic design flaw delphi 5 implementation of tthread. underlying windows thread started in constructor of tthread. leads race describe.
in delphi 6 version of rtl, thread start mechanism changed. delphi 6 onwards, thread started in tthread.afterconstruction. , runs after constructor completes. render code race free.
in delphi 6 , later, underlying windows thread created in tthread constructor, created suspended using create_suspended flag. in afterconstruction, long tthread.fcreatesuspended false, thread resumed.
one way work around issue in delphi 5 call inherited constructor last. this:
constructor tjvhiddevicereadthread.ctlcreate(const dev: tjvhiddevice); begin device := dev; numbytesread := 0; setlength(report, dev.caps.inputreportbytelength); inherited create(false); end; rather ugly know.
so, approach of creating thread suspended , resuming once constructor has completed better. approach mirrors how rtl solves problem in delphi 6 , up.
Comments
Post a Comment