Communicating between threads


(Christoph K) #1

I'm considering to implement the following architecture in my App:

ViewControllerDidLoad starts a thread (a C program).
This thread writes something into the view and then waits for input.

As soon as the main thread (ViewController) receives an endEditing() event, it should pass the String to the waiting thread which in turn interprets the String and writes back to the ViewControllers` view after which it goes into a waiting state.

Any suggestions how to implement this in Swift?


#2

Grand Central Dispatch is available on iOS/macOS, (I’m not sure if it’s fully supported on Linux yet). You could conusult old Apple’s WWDC video on how it works (there’s too many to include here).


(Alik Vovk) #3

Im curious whether you are talking about "Communicating between threads" or "Communicating between programs(processes)", because you are mentioning a C program.


(Christoph K) #4

I meant threads in one process space (program), not between programs.
That program is a Swift App using also C functions or portions.

Assume, you want to port a command line based program, like bc (unix calculator).
It prints results on the terminal line (UItextView) and has an input loop using e.g. getchar().

In a Swift App I cannot go down into a C function and call getchar() there. I need a way, to tell the C function that it has to wait for a piece of text (string) being available, e.g. when the user ends editing the UItextView.

So I thought I start a thread running the C program and waiting for a message from the main thread (Swift App)


(Christoph K) #5

my application would not be Linux, it would be iOS.


(Jonathan Prescott) #6

I'd like to ask some clarifying questions: using your example of bc, are you planning to have your "C" stream start up the bc program? If so, are you constrained because the "C" tool is binary only (you don't have access to the source code for the tool)?

If you have access to the source code, you could abstract out the relevant code, wrap it up in a "C" function like "void bc(const char* input, char* output)", and in your ViewController you would call bc with the text (converted to C-string) and a character string buffer internal to view controller to receive the result. When bc returns, you take the resulting string and update the view. If the function is going to take a long time, you might want to run in a dispatch queue, so it runs on a background thread.

If you have to use the actual "C" program binary, you will have to set up pipes, or some other inter-process mechanism, to feed the string from the text field into the stdin stream of the tool binary, and get the text string from stdout.


(Quinn “The Eskimo!”) #7

ViewControllerDidLoad starts a thread (a C program).

I strongly recommend that you not start threads in your view controller. View controllers are main-thread-only objects, and if you start running threaded code in them you run the risk of having the view controller being deallocated by a secondary thread. See The Deallocation Problem section of Technote 2109 Simple and Reliable Threading with NSOperation for details.


With regards your inter-thread communication problem, if your existing C code is calling getchar then you are going to have problems because that function always reads from stdin, and it’s not reasonable for you to repurpose stdin for inter-thread communication. If you can change it to use fgetc, or something similar, then you could reasonable set up this communication using pipes, a socket pair, or whatever.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple


(Christoph K) #8

I have the full source of the C program. So it's not like doing an exec() of some external program.

Assume something like:

#include <stdio.h>
#include <readline/readline.h>

#ifdef TEST
int main() {
    return (calc());
}
#endif

void interpret(char *);

int calc()
{
     char *str;

     while(1) {
         printf("\n>>");
         str=readline(NULL);
         interpret(str);
     }
}
void interpret(char * str) {
       printf("%s",str);
}

(Christoph K) #9

Thanks, Quinn, for the caveat.


(Christoph K) #10

I will not stick slavishly with getchar(), since I have to give up stdin anyway. The "line of text" will come from a text selection or a line wrap (ENTER) on the keyboard (what is the correct term for this sliding in keyboard panel anyway?)

--
Christoph


(Alik Vovk) #11

Your options are either: Import this file in Swift project and add import to the Bridging Header. But if your C program would be more complex that it couldn't been rewritten in Swift, or you would need stdin/stdout I would suggest running it as a process with Process where you can define your own input/output streams.


(Jonathan Prescott) #12

If you are already getting the text string from the ViewController, why not just call interpret(str), where the "str" is a C-version of the String/NSString value from the text field in the view? Instead of doing a printf, return another string. Why do you need the read-eval-print loop?


(Christoph K) #13

BTW, how does one cite the contents of a message one is responing to in this forum?

First off: I'm not about to rewrite the C program in Swift. That's absolutely outside of any consideraton in this case.

a) complexity
b) speed

Second: stdout/stderr is already successfully redirected to the textView (see otherthread in this forum).

Will think about your idea of calling the program that way but I don't see much chance.

Imagine the program is a Lisp interpreter.

--
Christoph


(Jonathan Prescott) #14

The program I'm linking to with Swift is CLIPS, C-Language Inference Production System, a rules-based expert system very similar to Lisp, which is why I suggested that approach.. Similar issues. However, amongst all the other interfaces in the package, there is an eval(string) call that allows one to pass a string into the interpreter and get the result string back. I've also wired up stdout and stderr into the rules engine I/O system through the use of the built-in I/O router system within the package, but, you seem to have stdout/stderr covered.

Never considered that you would re-write interpreter in Swift.


(Saleem Abdulrasool) #15

libdispatch should be usable on Windows, Linux, android, and FreeBSD. If it is not working properly, that is something that is a bug and needs to be looked into.