How can I force my window to keep itself updated? - c++builder

Final Update
The solution was to create a TTimer, set its Interval to any value greater than 0, and assign its OnTimer property to an empty function.
I have a TThread that adds new controls to the main form at regular intervals, via Queue(). But the queued functions are never executed until the form receives user input, or the cursor moves over it, and then it executes all the queued functions at once.
With careful logging I have determined conclusively that the functions are being queued as intended by the thread. They simply aren't being executed by the main VCL loop until the form gets user interaction.
It's as if the main application loop doesn't run when there is no user interaction.
How can I force the form to execute queued functions immediately?
If it matters, the form and TThread are created by a .dll, which is called by another .dll, which itself is called by a console application.
Like this:
console application -> dll -> dll created by C++ Builder
Edit
void __fastcall GirkovArpa::Execute() {
while (!Terminated) {
if (GlobalMessageQueue.size() > 0) {
EnterCriticalSection(&myCritSect);
std::cout << ""; // this line is required, else thread won't execute
std::string GlobalMessage = GlobalMessageQueue.at(0);
std::string copy;
copy.assign(GlobalMessage);
GlobalMessageQueue.erase(GlobalMessageQueue.begin());
LeaveCriticalSection(&myCritSect);
Queue([&, copy]() {
// do stuff
});
}
}
}
Edit 2
Node.JS console app => Node DLL addon => C++Builder GUI DLL
My console application is specifically NodeJS. It loads a "NodeJS addon" (a type of DLL), which loads the DLL created with C++ Builder, which exports this function:
void myExportedFunction(const char *str) {
EnterCriticalSection(&myCritSect);
GlobalMessageQueue.push_back(std::string(str));
// CheckSynchronize();
LeaveCriticalSection(&myCritSect);
}
If CheckSynchronize() is not commented out, I get a Segmentation Fault error.
My TThread runs on an infinite loop, checking GlobalMessageQueue, and if it finds it's not empty, it queues a lambda which creates a TControl on the main form.
But the queued lambdas are not executed until the user interacts with the window (simply moving the cursor over the window will suffice).
Edit 3
Here is my full lambda:
Queue([&, copy]() {
std::vector<std::string> words;
boost::split(words, copy, boost::is_any_of(" "));
// CREATE $TControl $Name $Text $Parent
if (words.at(0) == "CREATE") {
if (words.at(1) == "TEXTBOX") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TEdit *textbox = new TEdit(form);
textbox->Parent = form;
textbox->Name = words.at(2).c_str();
textbox->Text = words.at(3).c_str();
textbox->Show();
textbox->OnClick = MyForm->OnClick;
}
if (words.at(1) == "RADIO") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TRadioButton *radio = new TRadioButton(form);
radio->Parent = form;
radio->Name = words.at(2).c_str();
radio->Caption = words.at(3).c_str();
radio->Show();
radio->OnClick = MyForm->OnClick;
}
if (words.at(1) == "BUTTON") {
String formName = stringToString(words.at(4));
TForm *form = getFormByName(formName);
TButton *button = new TButton(form);
button->Parent = form;
button->Name = words.at(2).c_str();
button->Caption = words.at(3).c_str();
button->Show();
button->OnClick = MyForm->OnClick;
}
if (words.at(1) == "FORM") {
createDialog(words.at(2).c_str(), words.at(3).c_str());
}
}
if (words.at(0) == "CHANGE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(form->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue value;
if (prop->PropertyType->TypeKind == tkUString) {
value = TValue::From<UnicodeString>(words.at(3).c_str());
} else if (prop->PropertyType->TypeKind == tkInteger) {
value = TValue::From<Integer>(StrToInt(words.at(3).c_str()));
} else {
std::cout << "ERROR" << std::endl;
}
prop->SetValue(form, value);
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(control->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue value;
if (prop->PropertyType->TypeKind == tkUString) {
value = TValue::From<UnicodeString>(words.at(3).c_str());
} else if (prop->PropertyType->TypeKind == tkInteger) {
value = TValue::From<Integer>(StrToInt(words.at(3).c_str()));
} else {
std::cout << "ERROR" << std::endl;
}
prop->SetValue(control, value);
}
}
}
}
// GET NAME PROP
if (words.at(0) == "GET") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(form->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue result = prop->GetValue(form);
if (result.Kind == tkUString) {
String leString = result.AsString();
std::wstring w(std::wstring(leString.t_str()));
std::string STR(w.begin(), w.end());
std::string output = words.at(1) + " " + words.at(2);
String o = output.c_str();
tellJavaScript(AnsiString(o + ": " + leString).c_str());
} else if (result.Kind == tkInteger) {
int result_int = result.AsInteger();
String result_String = IntToStr(result_int);
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
} else {
// assume boolean
String result_String = BoolToStr(result.AsBoolean());
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
}
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
TRttiContext ctx;
TRttiType *type = ctx.GetType(control->ClassInfo());
TRttiProperty *prop = type->GetProperty(words.at(2).c_str());
TValue result = prop->GetValue(control);
if (result.Kind == tkUString) {
String leString = result.AsString();
std::wstring w(std::wstring(leString.t_str()));
std::string STR(w.begin(), w.end());
std::string output = words.at(1) + " " + words.at(2);
String o = output.c_str();
tellJavaScript(AnsiString(o + ": " + leString).c_str());
} else if (result.Kind == tkInteger) {
int result_int = result.AsInteger();
String result_String = IntToStr(result_int);
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
} else {
// assume boolean
String result_String = BoolToStr(result.AsBoolean());
String name = words.at(1).c_str();
String prop = words.at(2).c_str();
tellJavaScript(AnsiString(name + " " + prop + ": " + result_String).c_str());
}
}
}
}
}
if (words.at(0) == "DELETE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
form->Close();
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
control->Free();
}
}
}
}
if (words.at(0) == "EXECUTE") {
for (int j = 0; j < Screen->FormCount; j++) {
TForm *form = Screen->Forms[j];
if (form->Name == words.at(1).c_str()) {
std::cout << "EXECUTE <<" << words.at(2) << ">>" << std::endl;
TRttiContext context;
TRttiType *rttiType = context.GetType(form->ClassType());
TRttiMethod *method = rttiType->GetMethod(words.at(2).c_str());
DynamicArray<TRttiParameter *> parameters = method->GetParameters();
TValue args[10];
if (parameters.Length) {
for (int y = parameters.Low; y <= parameters.High; y++) {
String paramType = parameters[y]->ParamType->ToString();
if (paramType == "UnicodeString") {
args[y] = TValue::From<UnicodeString>(stringToString(words.at(y + 3)));
} else if (paramType == "Integer") {
args[y] = TValue::From<Integer>(StrToInt(stringToString(words.at(y + 3))));
}
}
TValue value = method->Invoke(form, args, parameters.High);
} else {
TValue value = method->Invoke(form, NULL, -1);
}
}
for (int i = 0; i < form->ControlCount; i++) {
TControl *control = form->Controls[i];
if (control->Name == words.at(1).c_str()) {
std::cout << "EXECUTE <<" << words.at(2) << ">>" << std::endl;
TRttiContext context;
TRttiType *rttiType = context.GetType(control->ClassType());
TRttiMethod *method = rttiType->GetMethod(words.at(2).c_str());
DynamicArray<TRttiParameter *> parameters = method->GetParameters();
TValue args[10];
if (parameters.Length) {
for (int y = parameters.Low; y <= parameters.High; y++) {
String paramType = parameters[y]->ParamType->ToString();
if (paramType == "UnicodeString") {
args[y] = TValue::From<UnicodeString>(stringToString(words.at(y + 3)));
} else if (paramType == "Integer") {
args[y] = TValue::From<Integer>(StrToInt(stringToString(words.at(y + 3))));
}
}
TValue value = method->Invoke(control, args, parameters.High);
} else {
TValue value = method->Invoke(control, NULL, -1);
}
}
}
}
}
});

It's as if the main application loop doesn't run when there is no user interaction.
It doesn't, actually. Well, more accurately, when there is no pending window messages at all. Once the main thread's message queue is emptied, the VCL calls the Win32 WaitMessage() function, which blocks the calling thread until a new message appears in the message queue. Even traditional non-VCL message loops tend to block the calling thread when there are no messages to process.
How can I force the form to execute queued functions immediately?
You can't force it.
If it matters, the form and TThread are created by a .dll, which is called by another .dll, which itself is called by a console application.
It DOES matter, because TThread::Queue() and TThread:::Synchronize() DO NOT work well inside of a DLL.
TThread::Queue() and TThread::Synchronize() put their requests into an internal queue inside the RTL, set a signal to indicate the queue has pending requests, and then post a message to the TApplication window to "wake up" the main thread (in case the message loop is "sleeping" waiting for a new message to arrive). That request queue is processed at the main thread's earliest convenience.
By default, a VCL message loop processes the TThread queue only when:
the message loop enters an idle state, after all pending messages have been processed and the message queue becomes empty.
the TApplication window receives the "wake up" message.
When the TThread queue is inside a DLL, and the DLL is not sharing the same RTL instance with the main EXE, then the main message loop in the EXE does not know about the TThread queue in the DLL, so it can't process the pending requests during idle times. That just leaves the "wake up" message, which the DLL will post to its own TApplication instance, not to the main EXE's TApplication. The main thread message loop will still dispatch window messages to a DLL's TApplication window.
To solve this, you will have to either:
enable Runtime Packages in the DLL and main EXE, or even change the DLL to be a Package, so that they can share common instances of the RTL and VCL. That does mean you will have to deploy the RTL and VCL .bpl files with your app, though.
export a function from your DLL that calls the RTL's CheckSynchronize() function, and then call that DLL function in your EXE code periodically, such as in a UI timer, or in the TApplication.OnIdle event, etc.

You're correct that the main loop of a typical Windows program does not run until there's some sort of input (usually user input, but there are other kinds as well).
I'm not familiar with the C++ Builder framework.
If you have control of code that makes the main loop, you can modify it to process additional sources of information, such as watching for another thread to signal a synchronization object.
Other options:
Have the thread that's adding items to the queue post a custom message to the main thread's window (or just a thread message) whenever it does one of its regular updates.
Set up a timer on the main thread. It will periodically "wake up" the main loop, just as the user input would.

Related

Modifying countdown() method to display parameters in VS ASP.Net Core MVC

Task: Modify the code for Countdown() method so it starts counting down at the start parameter, ends at the end parameter, and displays the message parameter when the countdown is done.
Current code: [Route("[action]/{start}/{end?}/{message?}")] public IActionResult Countdown(int start, int end = 0, string message = "") { string contentString = "Counting down:\n"; for(int i = start; i >= 0; i--) { contentString += i + "\n"; } return Content(contentString); }
enter image description here
I am not sure what's your expected result. The current code works but it just do a loop and then output a string:
[Route("[action]/{start}/{end?}/{message?}")]
public IActionResult Countdown(int start, int end = 0, string message = "")
{
string contentString = "Counting down:\n";
for (int i = start; i >= end; i--)
{
contentString += i + "\n";
}
return Content(contentString);
}
If you want to achieve a countdown timer, I think you should do it combined with your frontend, maybe you can provide us more information.

How to get function definition/signature as a string in Clang?

How can I get a function's signature (or at least the entire definition?) as a string using Clang/Libclang, assuming I have its CXCursor or so?
I think that the definition may be somehow obtainable by using the cursor's extents, but I don't really know how (what function to use).
You can use this simple code to get prototype of a function ( name, return type, count of arguments and arguments[name,data type]).
string Convert(const CXString& s)
{
string result = clang_getCString(s);
clang_disposeString(s);
return result;
}
void print_function_prototype(CXCursor cursor)
{
// TODO : Print data!
auto type = clang_getCursorType(cursor);
auto function_name = Convert(clang_getCursorSpelling(cursor));
auto return_type = Convert(clang_getTypeSpelling(clang_getResultType(type)));
int num_args = clang_Cursor_getNumArguments(cursor);
for (int i = 0; i < num_args; ++i)
{
auto arg_cursor = clang_Cursor_getArgument(cursor, i);
auto arg_name = Convert(clang_getCursorSpelling(arg_cursor));
if (arg_name.empty())
{
arg_name = "no name!";
}
auto arg_data_type = Convert(clang_getTypeSpelling(clang_getArgType(type, i)));
}
}
CXChildVisitResult functionVisitor(CXCursor cursor, CXCursor /* parent */, CXClientData /* clientData */)
{
if (clang_Location_isFromMainFile(clang_getCursorLocation(cursor)) == 0)
return CXChildVisit_Continue;
CXCursorKind kind = clang_getCursorKind(cursor);
if ((kind == CXCursorKind::CXCursor_FunctionDecl || kind == CXCursorKind::CXCursor_CXXMethod || kind == CXCursorKind::CXCursor_FunctionTemplate || \
kind == CXCursorKind::CXCursor_Constructor))
{
print_function_prototype(cursor);
}
return CXChildVisit_Continue;
}
You could try using clang_Cursor_getMangling() and demangle the result in order to get the complete definition.
I'm using the following for a project I am working on and it works great for the definition. TL&DR clang_getCursorPrettyPrinted with the policy TerseOutput set to true.
std::string getStdString(const CXString &s)
{
std::string rv = clang_getCString(s);
clang_disposeString(s);
return rv;
}
bool isFunctionImplementation(CXCursor &cursor,std::string &decl,std::string &filename,unsigned &lineno)
{
std::string cs = getStdString(clang_getCursorPrettyPrinted(cursor,nullptr));
if (cs.find('{') == std::string::npos) // Just a declaration, not the "meat" of the function, so we dont care
return false;
clang::LangOptions lo;
struct clang::PrintingPolicy pol(lo);
pol.adjustForCPlusPlus();
pol.TerseOutput = true;
pol.FullyQualifiedName = true;
decl = getStdString(clang_getCursorPrettyPrinted(cursor,&pol));
CXSourceLocation location = clang_getCursorLocation( cursor );
CXFile f;
lineno = 0;
filename = "(None)";
clang_getSpellingLocation(location,&f,&lineno,nullptr,nullptr);
if (lineno)
{
filename = getStdString(clang_File_tryGetRealPathName(f));
}
return isAllowedDirectory(filename);
}
This one checks if the function call is "meat" or just a definition. Obviously you can adjust as needed, including writing your own isAllowedDirectory function. Just pass the cursor, two strings and an unsigned into this as you walk your AST when you hit a declaration type.
I use the following, shorter way with clang 10 (though its using a matcher, not a cursor):
The 2 helper functions are general helpers to get the code snippet as a string.
// helper function 1: find position of end of token
SourceLocation
end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm)
{
using namespace clang;
LangOptions lopt;
return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt);
}
// helper function 2:
std::string getSymbolString(clang::SourceManager & sm,
const clang::SourceRange & range)
{
return std::string(sm.getCharacterData(range.getBegin()),
sm.getCharacterData(end_of_the_end(range.getEnd(), sm)));
}
The actual code snippet to get the function declaration string is:
// ... in run() of a matcher:
virtual void run(corct::result_t const & result) override
{
using namespace clang;
FunctionDecl * f_decl = const_cast<FunctionDecl *>(
result.Nodes.getNodeAs<FunctionDecl>(fd_bd_name_));
if(f_decl) {
SourceManager & sm(result.Context->getSourceManager());
FunctionDecl * f_decl = const_cast<FunctionDecl *>(
result.Nodes.getNodeAs<FunctionDecl>(fd_bd_name_));
auto full_decl_string =
getSymbolString(sm, f_decl->DeclaratorDecl::getSourceRange());
}
}
This will output inline bool test2(std::string const & str, std::vector<std::string> & sss) for the following function:
inline bool test2(std::string const & str, std::vector<std::string> & sss)
{
return true;
}

Indy Http Server with resume support

I have written an indy http server, I want to serve file download with resume support. When I use IDM to download file, the download is single threaded:
Note that the Resume capability is Yes, but When I pause and resume the download, It starts form beginning.
My Indy Http Server is as:
void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext,
TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
Beep(1000, 100);
string fileName = ExtractFileDir(Application->ExeName) + ARequestInfo->Document;
fileName = fileName.replace("/", "\\");
TFileStream *stream = new TFileStream(fileName, fmOpenRead | fmShareDenyNone);
int start = 0, end = 0;
string range = ARequestInfo->Range;
if(!range.empty())
{
int dash_pos = range.find("-");
start = range.substr(0, dash_pos).intValue();
end = range.substr(dash_pos + 1).intValue();
if(end == 0) // Endless Range: start-
end = stream->Size;
}
else
{
start = 0;
end = stream->Size;
}
OutputDebugStringW(string("ctx=[] start=[] end=[]") <<
IntToHex((int)AContext, 8) << start << end);
stream->Seek((__int64)start, soBeginning);
AResponseInfo->ContentStream = stream;
AResponseInfo->FreeContentStream = true;
AResponseInfo->ContentLength = stream->Size;
if(!range.empty())
{
AResponseInfo->ContentRangeStart = start;
AResponseInfo->ContentRangeEnd = end;
AResponseInfo->ResponseNo = 206;
AResponseInfo->ContentRangeInstanceLength = end + 1;
AResponseInfo->ContentLength = end - start + 1;
AResponseInfo->AcceptRanges = "bytes";
}
AResponseInfo->WriteHeader();
AResponseInfo->WriteContent();
}
any help would be appreciated.
The IdCustomHTTPServer unit has a TIdHTTPRangeStream helper class for this very purpose.
If the client requests a ranged download, create an instance of TIdHTTPRangeStream and pass it your intended TStream and the client's requested range, then assign it as the ContentStream to be sent. TIdHTTPRangeStream also has a ResponseCode property that you need to assign to the response's ResponseNo property.
For example:
void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
// create file stream ...
// THTTPServer parses the ranges for you
if (ARequestInfo->Ranges->Count > 0)
{
if (ARequestInfo->Ranges->Count > 1)
{
AResponseInfo->ResponseNo = 416;
return;
}
TIdEntityRange *range = ARequestInfo->Ranges->Range[0];
TIdHTTPRangeStream *rstream = new TIdHTTPRangeStream(stream, range->StartPos, range->EndPos, true);
AResponseInfo->ResponseNo = rstream->ResponseCode;
AResponseInfo->ContentRangeStart = rstream->RangeStart;
AResponseInfo->ContentRangeEnd = rstream->RangeEnd;
AResponseInfo->ContentStream = rstream;
AResponseInfo->AcceptRanges = "bytes";
}
else
{
AResponseInfo->ContentStream = stream;
}
// no need to seek the target stream manually
// no need to set the ContentLength manually
// no need to call WriteHeader() and WriteContent() manually
//
// TIdHTTPServer handles all that for you internally!
}

Java: Indexoutofbound in Cellualar Automaton

Here is my code for a cellular automaton I am working on:
UPDATE:
public class Lif1ID {
private Rule rule;
private int stepCount;
public static void main (String [ ] args) {
Lif1ID simulation = new Lif1ID ( );
simulation.processArgs (args);
simulation.producePBM ( ); LINE 9
}
// Print, in Portable Bitmap format, the image corresponding to the rule and step count
// specified on the command line.
public void producePBM ( ) {
int width = (stepCount*2+1);
System.out.println("P1 " + width + " " + (stepCount+1));
String prev_string = "";
// constructs dummy first line of rule
for (int i = 0; i < width; i++){
if (i == stepCount+1){
prev_string += "1";
} else {
prev_string += "0";
}
}
// contructs and prints out all lines prescribed by the rule, including the first
for (int i = 0; i < stepCount; i++) {
String next_string = "";
for (int j = 0; j < width; j++) {
// prints next line, one character at a time
System.out.print(prev_string.charAt(j) + " ");
// specifies cases for the edges as well as for normal inputs to Rule
if (j == 0) {
next_string += rule.output(0, Character.getNumericValue(prev_string.charAt(0)), Character.getNumericValue(prev_string.charAt(1)));
} else if (j == width-1) {
next_string += rule.output(Character.getNumericValue(prev_string.charAt(width-2)), Character.getNumericValue(prev_string.charAt(width-1)), 0);
} else {
String rule_input = prev_string.substring(j-1, j+2);
int first = Character.getNumericValue(rule_input.charAt(0));
int second = Character.getNumericValue(rule_input.charAt(1));
int third = Character.getNumericValue(rule_input.charAt(2));
next_string += rule.output(first, second, third); LINE 43
}
}
// sets prev_string to next_string so that string will be the next string in line to be printed
prev_string = next_string;
System.out.println();
}
}
// Retrieve the command-line arguments, and convert them to values for the rule number
// and the timestep count.
private void processArgs (String [ ] args) {
if (args.length != 2) {
System.err.println ("Usage: java Life1D rule# rowcount");
System.exit (1);
}
try {
rule = new Rule (Integer.parseInt(args[0]));
} catch (Exception ex) {
System.err.println ("The first argument must specify a rule number.");
System.exit (1);
}
try {
stepCount = Integer.parseInt (args[1]);
} catch (Exception ex) {
System.err.println ("The second argument must specify the number of lines in the output.");
System.exit (1);
}
if (stepCount < 1) {
System.err.println ("The number of output lines must be a positive number.");
System.exit (1);
}
}
}
class Rule {
private int a, b, c;
private String rulebin;
public Rule (int ruleNum) {
rulebin = convertToBinary(ruleNum);
}
private String convertToBinary(int input) // get the binary presentation as you want
{ // if the input is 2 you'll get "00000010"
String binary = "";
for (int i = 0; i < 8; i++){
if ((1 << i & input) != 0)
binary += "1";
else
binary+= "0";
}
binary = new StringBuffer(binary).reverse().toString();
return binary;
}
// Return the output that this rule prescribes for the given input.
// a, b, and c are each either 1 or 0; 4*a+2*b+c is the input for the rule.
public char output (int a, int b, int c) {
return rulebin.charAt(7 - 4*a + 2*b + c); LINE 106
}
}
Here is the error message I get when I type in rule 30 with 3 timesteps:
java Life1D 30 3
UPDATED error message:
P1 7 4
0 0 0 0Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 151
at java.lang.String.charAt(String.java:686)
at Rule.output(Life1D.java:106)
at Life1D.producePBM(Life1D.java:43)
at Life1D.main(Life1D.java:9)
The corresponding lines are noted in the code. Why am I getting this error, and how can I fix it? I've been trying to find the error for hours, and it'll a blessing if I could be helped.
The problem is that Rule.output() expects three int parameters, but what you're calling it with on the line
next_string += rule.output(0, prev_string.charAt(0), prev_string.charAt(1));
is actually an int and then 2 chars. Now, the actual character is '0', but due to the implicit conversion the language does for you, you get the ASCII code of '0', which is 48 and that's what's passed to the function Rule.output().
Now, to fix this problem you need to use the method Character.getNumericValue() like so:
next_string += rule.output(0, Character.getNumericValue(prev_string.charAt(0)), Character.getNumericValue(prev_string.charAt(1)));
Don't forget to change the other two invocations of Rule.output()
However, note that this is not the only problem in your code, as I'm still getting String index out of range: 7, because the parameters with which the Rule.output() method is called with are now all 0, but I've answered your original question. If you need more help, let me know.

Unable to acquire a mutex held by a ACE_Condition wait

I have the following code which is used to Push and Pend from a queue. The caller code has multiple MsgQ objects. It is possible that the Push and the Pend functions are waiting on the _notFull->wait() and the _notEmpty->wait() conditional waits. These waits are protected by the _mut mutex. The notFull and the notEmpty waits operate on the empty and full variables.
When the destructor is called, the _deleteQueue is called internally, from which I would like to signal to the waiting threads to cleanup and stop waiting for a signal to come. Once that is done, I delete my objects. However, in the _deleteQueue function, when I attempt to do _mut->acquire(), I am unable to acquire the mutex. Even if I ignore the acquire, I am unable to broadcast to these waiting threads. Where am I going wrong?
Thanks,
Vikram.
MsgQ::~MsgQ()
{
_deleteQueue();
delete _mut;_mut=NULL;
delete _notFull;_notFull=NULL;
delete _notEmpty;_notEmpty=NULL;
delete _PostMutex; _PostMutex = NULL;
delete _PendMutex; _PendMutex = NULL;
delete _PostInProgressMutex; _PostInProgressMutex = NULL;
delete _PendInProgressMutex; _PendInProgressMutex = NULL;
delete _DisconnectMutex; _DisconnectMutex = NULL;
free( _ptrQueue ); _ptrQueue = NULL;
}
int MsgQ::Post(Message* msg)
{
_PostMutex->acquire();
_postInProgress++;
_PostMutex->release();
if (msg)
msg->print();
_mut->acquire();
while (full)
{
_notFull->wait();
}
if (!_disconnectInProgress)
_queuePush(msg);
_mut->release();
_PostMutex->acquire();
_postInProgress--;
if (_postInProgress==0)
{
_PostInProgressMutex->signal();
}
_PostMutex->release();
return _notEmpty->signal();
}
int MsgQ::Pend(Message*& msg)
{
_PendMutex->acquire();
_pendInProgress++;
_PendMutex->release();
_mut->acquire();
while (empty)
_notEmpty->wait();
if (!_disconnectInProgress)
{
_queuePop(msg);
}
_mut->release();
_PendMutex->acquire();
_pendInProgress--;
if (_pendInProgress == 0)
{
_PendInProgressMutex->signal();
}
_PendMutex->release();
return _notFull->signal();
}
void MsgQ::_deleteQueue ()
{
_PostMutex->acquire();
if (_postInProgress != 0)
{
_PostMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
full = 0;
_notFull->broadcast();
_mut->release();
_PostInProgressMutex->wait();
}
else
{
_PostMutex->release();
}
_PendMutex->acquire();
if (_pendInProgress != 0)
{
_PendMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
empty = 0;
_notEmpty->broadcast();
_mut->release();
_PendInProgressMutex->wait();
}
else
{
_PendMutex->release();
}
}
void MsgQ::_initQueue()
{
_ptrQueue = (Message **)(malloc (size * sizeof (Message*)));
if (_ptrQueue == NULL)
{
cout << "queue could not be created!" << endl;
}
else
{
for (int i = 0; i < size; i++)
*(_ptrQueue + i) = NULL;
empty = 1;
full = 0;
head = 0;
tail = 0;
try{
_mut = new ACE_Mutex() ;
_notFull = new ACE_Condition<ACE_Mutex>(*_mut);
_notEmpty = new ACE_Condition<ACE_Mutex>(*_mut);
_PostMutex = new ACE_Mutex();
_PendMutex = new ACE_Mutex();
_PostInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PostMutex);
_PendInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PendMutex);
_DisconnectMutex = new ACE_Mutex();
_postInProgress = 0;
_pendInProgress = 0;
_disconnectInProgress = false;
}catch(...){
cout << "you should not be here" << endl;
}
}
}
There seem to be many problems with the code so I would suggest reworking it:
You have a potential for deadlock because you are acquiring _mut before you go into a wait condition in both Post and Pend functions.
Instead of using acquire and release on a ACE_Mutex I would suggest looking at using ACE_Guard class which can acquire mutex when created and release it when destroyed.
Why not use ACE_Message_Queue instead of creating your own?

Resources