
What happens inside the program is very similar to a team of several people. Each team member has his own task and, most likely, his “workplace” to which no one except him should touch. Colleagues can give each other instructions and transmit some information about the work process. They can ask each other for help and can provide it. Like any team, they have a boss, whose task is to interact with the user and coordinate actions within the team.
With this view of the program, it comes to life, and everything that happens inside it begins to acquire some images. Having distributed all the work processes and tasks to the various "employees" you begin to understand how everything should work.
The source codes of the player, on which I once spent a lot of time, have long been gathering dust on the hard disk. I wrote this application for a year when the mood appeared. In the end, my enthusiasm dried up and the player was forgotten. And recently, I came up with the idea of architecture, which, as it turned out, fits perfectly with it - I’ll talk about it further. I will highlight the “workers” in the application, and assign roles in such a way that each employee has a clear, simplest, and understandable task.
Acquaintance
For starters, the most important member of the team is the singer. He bawls songs on the notes that he shoved. Naturally, no notes are processed in the program - it is just a replacement for the notion of a “music track”. A singer can be instructed to sing something, ask to stop, and ask to sing a little louder or quieter. Still, you can put the singer notes the next list of songs, so that he quickly moved from one song to another.
')
While the singer yells, someone must keep a list of songs that will be sung next. Here comes the sorter. Its task is to maintain a list of further played compositions in accordance with the playback mode that suits the user. When the singer finishes the song, he asks the sorter to give him notes from the next one. And he either gives them or throws up his hands, informing that the list is over, and there is no repetition. In addition, at any time, the boss can report that the user has changed the order of playback, and the sorter will have to make a new list.
The sorter only keeps the order of playback and he needs to know what songs are generally available. The audio library is responsible for keeping a complete list of songs and manipulating it (it seems there is such a word). Most often, it is the sorter who refers to his services when drawing up his list. The audio library can give a list of root folders, a list of the contents of each folder and information about any track in the audio library.
There is one more task. When a user adds a new folder with music to the audio library, this folder must be viewed and entered information about all the music found in the audio library. The audio library could also do this, but in this case it would be difficult to ensure simultaneous scanning of folders and proper functioning of the audio library. Let the search engine do this - it will accumulate all the changes that need to be made and transfer them to the audio library in one fell swoop in order to minimize delays when working with an audio library.
And the last, most responsible character - the chief. He is responsible for starting the work of his team and for interacting with the user. It controls the interface and lets you know the rest if the user wants something. The pause button is pressed - the chief asks the singer to stop. A composition has been added to the queue - the boss reports this to the sorter, and so on. In our case, this is most likely not needed, but even subordinates can turn to the boss if they need to help in something they cannot cope with. In this case, the boss can show who in the team can help.
Who are all these people?
I have never heard of such an architecture, but there is a possibility that something like this already exists. If you have heard about this - I will be grateful if you write about it in the comments. Despite the fact that I may have invented a bicycle, I will not stop - suddenly a mountain bike will turn out.
Let's get back to business. We must somehow name the performers. I thought about employees, personalities and minions, but I think the most appropriate word would be “character”. This term is impersonal enough to call it and anyone. And the idler and the nurse and the main villain. What should be the character?
First, he must have some freedom. Just the same as people in real life. You cannot force your employee to do something with the help of physical strength (I am for humane work). Therefore, it is impossible to directly call the functions of the character object - this would be similar to “puppelling”, and not to voluntary work. Instead, he should receive messages and respond to them whenever possible. It turns out that message transfer methods should be provided.
Secondly, for each participant in the process must be allocated its own thread. This will ensure their independence from each other.
Third, in order for streams not to spoil data while simultaneously accessing them, it is necessary to provide appropriate means. This is somewhat similar to the interaction of processes in the system and to the problems existing there.
About messages
The character sequentially processes the messages coming to him. If there are no messages, it can idle or perform some background work by periodically checking the message queue.
What should be the message? You can make a single type - universal, which can be used in all cases by setting the necessary parameters. Just like there is a universal concept of a function. But I try to avoid such decisions, since universality often complicates the implementation of simple actions. I prefer three simple ways covering all possible options for performing some action, one complex universal. This, of course, somewhat complicates learning to perform this action, but at times accelerates its application and improves the visibility of expressions. In addition, if the actions are broken down by type, this means that the machine can easily distinguish between them, and this, in turn, expands the possibilities of automation and optimization.
So, offhand, I can split the messages into three groups:
1) Tasks / assignments - someone wants a character to do some work. Example: when the user presses "play" the head asks the singer to begin the song.
2) Requests - a character may ask his colleague to give him some materials. When the requested (must be such a word) is ready for transmission, the applicant will receive a message from him with the necessary materials. Example: when a singer needs a new composition, he asks her for a sorter.
3) Event notifications - it may be that the activities of one character will depend on the actions of another. The commander needs to know when the singer changes the song to update the interface. For this, the commander needs to ask the singer to report a song change. And the singer, in turn, will send notification messages to all who asked for it.
Together with the messages you can send any materials or parameters. In fact, the only difference between sending a message and calling a function is that messages are sent to characters and can be carried out while functions are triggered immediately and relate to objects.
Then I thought to paint all the messages that each character of the player understands, but the list turned out to be rather large and I decided that it was rather useless. So I will start to finish.
Conclusion
The presented architecture allows quite a visual representation of a multithreaded application. In addition, the division of all components of the program into objects and performers makes the structure of the program clearer. With team development, it becomes clearer how to divide responsibilities - each programmer can take on a character.
It turns out that the program is just a room with several employees and working materials. A dream come true programmer. I can explain how the program works. I am sure that if the concept is easy to imagine, then it has a chance.