It is All about Traffic, and Programming
Search
Archives
0 visitors online now
0 guests, 0 members

Wuping Xin

The Move Constructor: A Linking Pitfall of Qt Library with Different Compilers

Move constructor is a C++11 feature from ISO/IEC14882:2011.  It enhanced the old-school C++ copy constructor by moving the resource of an object, instead of member-wise copying.  It is faster than a copy constructor.  Thus a C++11 compiler will generate six special member functions for a C++ object, including  move constructor and move assignment operator:

  • Default Constructor
  • Copy Constructor
  • Copy Assignment Operator
  • Destructor
  • Move Constructor
  • Move Assignment Operator

We are not going to discuss C++11 Move Constructor in details here –  better details and better explanations are there, and there.

The motivation of  this article,  is not to discuss the semantics or usage of Move Constructor,  but an interesting debugging experience, and the lessons learned which involves C++11 move constructor.

Long story short – I have been working on developing an advanced Qt-based C++ plugin DLL for a host software developed in Qt 4.8.7.   I was using Visual C++ 2010 compiler, and the Qt for VS2010 official release for commercial applications.

The plugin DLL is supposed to be dynamically loaded by the host via Qt’s QLibrary API (see my previous article on this subject), which internally will call Microsoft’s Win32 API LoadLibrary.  Somehow, I got the following error, when trying to load the DLL into the host software:

34f8:3518 @ 01570140 – LdrpGetProcedureAddress – INFO: Locating procedure “AcdssPluginFactory” by name
34f8:3518 @ 01570140 – LdrpNameToOrdinal – WARNING: Procedure “AcdssPluginFactory” could not be located in DLL at base 0x0B630000
34f8:3518 @ 01570140 – LdrpReportError – WARNING: Locating export “AcdssPluginFactory” for DLL “Unknown” failed with status: 0xc0000139
34f8:1168 @ 01570265 – LdrpReportError – ERROR: Locating export “??4QString@@QAEAAV0@$$QAV0@@Z” for DLL “C:\Program Files (x86)\…\plugins\acdssplugin.DLL” failed with status: 0xc0000139

The above debug messages were generated by GFlags Utility, which comes with Debugging Tools for Windows. You can find the most advanced debugging techniques including how to use GFlags utility from the excellent book Inside Windows Debugging.  In our case, we just need to set “Show Loader Snaps” flag, as shown in the figure.  This is a typical way of debugging LoadLibrary failures.

2016-10-12_21-41-26

Looking at the debug messages, it is simply pointing out that LoadLibrary fails because an exported function is missing from the image space – its C++ mangled name as  “??4QString@@QAEAAV0@$$QAV0@@Z”,  which can be interpreted as:


    ? = C++ mangled symbol
    ?4 = "operator="
    QString@ = the enclosing class, hence method name: QString::operator=
    @ = end of the scope
    Q = public
    A = no const and volatile qualifier
    E = __thiscall
    AAV0 = const ref to the first named class (QString) - the return value (const QString &)
    @ = end return type
    $$ = move constructor &&
    QAV0 = const pointer to first named class - QString * const
    @ = end parameter type
    @ = end parameters
    Z = function

So clearly, the host software was complaining that the Move Constructor of QString can not be located in any of the image space.  Upon further inspection of the host software, it is discovered it was compiled using VS2005.  QtCore4.dll does not have the Move Constructor generated with VC++ 2005 compiler.  

The solution is simple – just rebuilt the Qt 4.8.7 using VC++ 2005, and rebuilt the plugin DLL.  Above all, the lessons learned are:

Do NOT mix Qt library compiled with different compilers, EVEN with the same Qt Version.  Period.

Adaptive Signal Control: Cyclic, or not?

At LinkedIn Group Adaptive Traffic Signal Control Systems,  Dr. Andrei Reztsov,  an applied mathematician posted a link for his new paper

Self-Organizing Traffic Lights as an Upper Bound Estimate
Andrei Reztsov, Complex Systems 24(2).

 

Self-organizing traffic lights (SOTL) are considered a promising instrument for the development of more adaptive traffic systems. In this paper we explain why some well-promoted results obtained with the use of SOTL should be scrutinized and carefully reviewed. Current computational research projects based on SOTL should be reviewed too.

2015-07-25_19-31-18

For those interested,  Dr. Reztsov’s papers can be downloaded from SSRN.

I applaud this paper for its insights and for its logical and rigorous treatment from an mathematician to point out the methodological fallacies of SOTL or those type of second-by-second genre of real time signal control. I concur with the opinion of the paper. As far as I know, this appears the first to discuss the following aspects of adaptive signal control:

  • cyclic calculation/decision,
  • sub-cyclic calculation/decision, and
  • sec-by-sec decision.

Self-Organizing Traffic Light (SOTL), or sometimes  “Second-By-Second” control  refers to acyclic operations by internally manipulating phase force-off and phase hold commands so the signals do not operate on a cyclic basis. It is “second-by-second”,  in the sense the system monitors phases status and detectors inputs continuously,  and makes decisions to terminate or extend phases on a second-by-second or near second-by-second basis.  These are currently not within standard NTCIP C2F operations.

A centralized second-by-second control typically would result in high communication overhead due to the onerous second-by-second status monitoring at each individual phase and/or detector level. Also second-by-second control cannot be easily integrated with current NTCIP Center-2-Field framework, because  NTCIP is UDP based type of communication that cannot guarantee the receipt of data packets, thus not meeting the reliability requirement for second-by-second control. In practice it is typically implemented in a distributed manner at local controllers, and requires certain middle-tier mechanism (e.g., a field master, or a customized firmware embedded in the same cabinet, or an add-on module communicating with a standard SDLC port) to coordinate with adjacent intersections and cache the second-by-second commands without overwhelming the central system, if any.

Second-by-second type of control is flexible,  and effective when traffic demand is low to the extend of random arrivals. It is most effective when the network starts with empty streets – that is exactly where this type of control’s niche resides to best reshuffle the time resource – to accommodate the predicted arrival of platoons on a preferred route. It works well, only and only when there is time resource to exercise such “rescheduling”.

And that is  the problem.

The traffic signal optimization problem is fundamentally simple – it boils down to allocate either limited time resource (for oncoming vehicles),  or limited space resource (for queuing vehicles),  of at-grade intersections with competing traffic streams.

“At-grade intersections” means the system has to deal with competing traffic streams in a 2-D plane.  Both time and space resources are limited for at-grade intersections.  Time resource is limited,  because in practice  any at-grade intersection’s capacity will never exceed 1800 vphpl; space resource is limited, because it is constrained by available storage space.

The signal for each phase applies to the group of drivers, not an individual driver on an individual stop-release basis. When traffic is light,  the signals running second-by-second can favor the predicted on-coming traffic on a preferred route,  thus reducing perceived maximum waiting time for individual drivers, and improving individual driver satisfaction.

The challenge really comes when traffic becomes heavy and over-saturated.  In that case,  the available capacity of an intersection is not able to serve the demand, and the flexibility to shuffle the time resource for vehicle platoons is gone.

It is logical to believe that when traffic is light to the extent of pure random Poisson arrivals, SOTL behaves more like an enhanced actuated type of control; when traffic increases, SOTL would converge to cyclic no matter how the logic tries to reshuffle the time for individual vehicles.  The chain of reasoning is:

When traffic is light, the value of sec-by-sec may help individual driver  satisfaction due to its flexibility to freely terminates a phase, and due to the reduced MAX perceived delay time, but not primarily average delay. However, when demands increase, the benefits quickly diminish and average delay increases.  At certain range of traffic flow regime, sec-by-sec control  probably reduces capacity because of the increased lost-time from phase switches.  Remember,  phase switches have a cost of lost time which is non-trivia when traffic is not light.  Therefore, with traffic increasing, sec-by-sec will quickly converge to cyclic losing its point.

This explains my particular favor of a cyclic system and I found this paper is very interesting.

Convergence to cyclic and the effect of sec-by-sec of reducing MAX perceived delay instead of AVG delay renders such operation moot in practice, because:

  • When traffic is light as random arrivals, there is really not much need or systematic benefits of  running adaptive.  This is because a fully actuated setting can well handle light traffic conditions.  Favoring a route when traffic is light may well promote speeding and incur other  implications.

This also explains why sec by sec control by itself wouldn’t be working well for congested or heavy traffic, at least not as well as some of the literature reported.  It appears to me many before-and-after improvements were built on the base case of comparisons being poorly-tuned fixed time plans,  or not well-configured semi-coordinated operations.

In summary, using comments posted in the same LinkedIn Group, from Mr. Kevin Fehon:

It is logical that SOTL or similar systems must converge to a cyclical state with heavy demand and practical constraints (such as maximum wait time, driver expectations about fairness in distribution of delays, etc.). This is built-in in their operations, and  is supported by observation of existing non-cycle based systems in the field.  It appears that this convergence also cannot be as optimized as the operation of a system whose optimization assumes cyclical operation, especially when vehicle-actuated flexibility (phase re-service, phase sequence changes under different traffic conditions, etc.) is built into the system.

Advanced Aimsun API Programming (2)

Aimsun MicroAPI has a total of 444 functions,  in three header files:

  • AKIProxie
  • ANGConProxie
  • CIProxie

These functions are ported to Delphi language, and the following shows a demo of obtaining vehicle information:

Aimsun API-Delphi Demo 1: Obtaining Vehicle Information

  • First the exported functions are defined in the project file, as follows:
// AIMSUN API  Delphi Interface
// Ported by Wuping Xin
// Last Update @2014-03-21 20:23:55
//---------------------------------------------------

library AAPI_veh_info;

uses
  AAPI in 'AAPI.pas',
  AAPI_Util in 'AAPI_Util.pas',
  AKIProxie in 'AKIProxie.pas',
  ANGConProxie in 'ANGConProxie.pas',
  CIProxie in 'CIProxie.pas';

{$R *.res}

exports
  AAPILoad,
  AAPIInit,
  AAPIManage,
  AAPIPostManage,
  AAPIFinish,
  AAPIUnLoad,
  AAPIEnterVehicle,
  AAPIExitVehicle,
  AAPIEnterVehicleSection,
  AAPIExitVehicleSection,
  AAPIInternalName,
  AAPIPreRouteChoiceCalculation;

begin
  //
end.
  • Second,  the exported functions are actually implemented in unit AAPI.pas file, as follows:
unit AAPI;

interface
  function AAPILoad: Integer; cdecl;
  function AAPIInit: Integer; cdecl;
  function AAPIManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  function AAPIPostManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  function AAPIFinish: Integer; cdecl;
  function AAPIUnLoad: Integer; cdecl;

  function AAPIEnterVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  function AAPIExitVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  function AAPIEnterVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  function AAPIExitVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  function AAPIInternalName: PAnsiChar; cdecl;

  function AAPIPreRouteChoiceCalculation(aTime: Double; aTimeSta: Double):
      Integer; cdecl;

implementation

uses
  SysUtils, AKIProxie, ANGConProxie, CIProxie;

  function AAPIEnterVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIEnterVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIExitVehicle(aVehID: Integer; aSectionID: Integer): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIExitVehicleSection(aVehID: Integer; aSectionID: Integer; aTime:
      Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIFinish: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIInit: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIInternalName: PAnsiChar; cdecl;
  begin
    Result := 'AAPI_veh_info';
  end;

  function AAPILoad: Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  var
    lvVehInfo: InfVeh;
    lvNumOfSections, lvNumOfVehs, lvNumOfJunctions: Integer;
    lvSectionIdx, lvVehIdx, lvJunctionIdx: Integer;
    lvSectionID, lvJunctionID: Integer;
    lvVehInfoStr: string;
  begin
    try
      lvNumOfSections := AKIInfNetNbSectionsANG;

      for lvSectionIdx := 0 to lvNumOfSections - 1 do
      begin
        lvSectionID := AKIInfNetGetSectionANGId(lvSectionIdx);
        lvNumOfVehs := AKIVehStateGetNbVehiclesSection(lvSectionID, True);

        for lvVehIdx := 0 to lvNumOfVehs - 1 do
        begin
          lvVehInfo := AKIVehStateGetVehicleInfSection(lvSectionID, lvVehIdx);
          lvVehInfoStr := Format('Vehicle %d, Section %d, Lane %d, CurrentPos %f, CurrentSpeed %f',
            [
              lvVehInfo.idVeh,
              lvVehInfo.idSection,
              lvVehInfo.numberLane,
              lvVehInfo.CurrentPos,
              lvVehInfo.CurrentSpeed
            ]);

          AKIPrintString(PAnsiChar(AnsiString(lvVehInfoStr)));
        end;
      end;

      lvNumOfJunctions := AKIInfNetNbJunctions;

      for lvJunctionIdx := 0 to lvNumOfJunctions - 1 do
      begin
        lvJunctionID := AKIInfNetGetJunctionId(lvJunctionIdx);
        lvNumOfVehs := AKIVehStateGetNbVehiclesJunction(lvJunctionID);

        for lvVehIdx := 0 to lvNumOfVehs - 1 do
        begin
          lvVehInfo := AKIVehStateGetVehicleInfJunction(lvJunctionID, lvVehIdx);
          lvVehInfoStr := Format('Vehicle %d, Node %d, From %d, To %f, CurrentPos %f, CurrentSpeed %f',
            [
              lvVehInfo.idVeh,
              lvVehInfo.idJunction,
              lvVehInfo.idsectionFrom,
              lvVehInfo.idSectionTo,
              lvVehInfo.CurrentPos,
              lvVehInfo.CurrentSpeed
            ]);

          AKIPrintString(PAnsiChar(AnsiString(lvVehInfoStr)));
        end;


      end;

      Result := 0;
    finally
      //
    end;
  end;

  function AAPIPostManage(aTime: Double; aTimeSta: Double; aTimeTrans: Double;
      aSimStep: Double): Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIPreRouteChoiceCalculation(aTime: Double; aTimeSta: Double):
      Integer; cdecl;
  begin
    Result := 0;
  end;

  function AAPIUnLoad: Integer; cdecl;
  begin
    Result := 0;
  end;

end.

 The above demo and the ported Aimsun API in Object Pascal can be downloaded from here.

http://wupingxin.net/wx-files/aimsun_api_pascal.zip

 

Hushing the nagging screen from Syncrho Education Version

Synchro Education Edition – has a nagging screen EACH time the software is launched – Until you click “Accept”,  you will be going nowhere.

After “Accept” is clicked,  you will see the main UI water-marked with the line saying “Educational Use Only”.  Also you will experience a noticeable freezing period up to 1 or 2 seconds – the software is surreptitiously checking with a Trafficware server in Texas for any new version available, and verifying the license information.

This Fall semester I am teaching a Traffic Control & Simulation course at NYU-Poly, and get to use the Synchro academic version with some sort of frequency.  This nagging screen is becoming quite annoying to me – not to mention personally I tend to attribute this nagging trick as being somewhat paranoid and pointless, especially when the actual protection with Syncrho is shockingly weak.

I simply don’t like that each time I have to manually click the “Accept” button, in order to proceed. Don’t get me wrong,  this is not that I disagree with the terms,  just I don’t like manually doing it.  I would like to make a tool, and authorize the tool,  representing myself, to Agree and Accept to the license terms by clicking the “Accept”  button for me.

Therefore – with my tool of choice – AutoIt,  I prepared a little nifty script so that each time the software is launched, the computer itself will automatically click the button for me to Accept the terms – I don’t need to bother to move any of my fingers.

Wowooo – La!

The following is download link to the compiled version of the script, just put it anywhere on your computer’s desktop to replace the default Synchro shortcut lnkYou are still going to see the nagging screen appear, so you know what you are going to Accept,  but immediately it will be closed since the script, as authorized by you, and truly you,  automatically click the “Accept” button for you.  Besides,  the version checking window will be immediately closed as well,  and you won’t see the initial 1 or 2 seconds freezing period.  You can always to go to “Help” -> “Check for Updates” to do the explicit version check, yourself.

http://www.wupingxin.net/wx-files/synchro-8.7z