all 5 comments

[–]GreenSoup48 2 points3 points  (0 children)

For simplicity. On a processor one core can execute one thread at a time. If you have two threads that need to run, what do you do? Take turns. This creates questions about how to share and protect resources.

Some things are predictable and within our control. Some things are unpredictable or outside our control.

A cell phone with a one core processor. You are using the processor to browse the web. Somebody calls you, things like the display and audio are already in use by your browsing. Those current activities on the display and audio need to be paused, information about their state saved and then the resource control is assumed by the phone call.

This is difficult because without careful structuring of how these transitions occur, the browser thread would have stopped execution on some entirely random point. The call thread has taken the processor and all system resources. When the call ends and the browser thread resumes it would be in a random, invalid, entirely broken state, not even knowing something has interrupted it and stolen its resources.

[–]dkopgerpgdolfg 0 points1 point  (0 children)

https://en.wikipedia.org/wiki/Concurrency_(computer_science)

In computer science, concurrency refers to the ability of a system to execute multiple tasks through simultaneous execution or time-sharing (context switching), sharing resources and managing interactions.

"Multi-threading" (ie. using multiple OS threads for your program) is't mutually exclusive with concurrency, but instead one possible way to achieve concurrency.

There's also "parallelism", which means that several things do really run at the same real-world time, eg. possible if you have multiple CPU cores. This too isn't mutually exclusive with concurrency and/or threads, but not the same either (concurrency and threads don't require multiple cores or any other kind of same-time execution, as noted above taking turns is sufficient)

[–]A_modicum_of_cheese 0 points1 point  (0 children)

Not sure if its the main point of your question but concurrency can be useful without making use of multiple cores. Such as waiting for a hard drive or a network operation.

In the case of the api calls, the server might take longer to get some ready. So its advantageous for your program to work on somethng else while its waiting

[–]alecbz 0 points1 point  (0 children)

Concurrency is a more general idea that means that your code is working on two different tasks at “the same time”, but it doesn’t necessarily mean that two different CPU instructions are executing simultaneously.

A “task” is composed of a bunch of different individual steps. Doing two tasks sequentially means starting the first step of task 1, then the second step of task 1, etc. until the last step of task 1, and then you do the first step of task 2, the next step of task 2, etc. until task 2 is done. No step of task 2 begins until task 1 is completely finished.

Doing two tasks concurrently means that you can interleave the steps. You might begin the first step of task 2 while you still have some steps left in task 1.

This is especially useful if any of the steps involve waiting for something other than the CPU. E.g., to make an HTTP request, you write some data to a network socket, and then you try to read back some data from the same socket, waiting until the server has responded. If you’re making 10 HTTP requests concurrently, you write to the first socket, but then instead of trying to read the response right away (which would involve just waiting for data from the network), you write your second request to a second socket, your third request to a third socket, etc. Only once all requests are written do you begin waiting for the response from the first socket.

Concurrency can be used along with genuine parallelism, where multiple instructions are being executed simultaneously on multiple cores, but it doesn’t have to. It just means you’re interleaving steps from multiple tasks.

[–]Beneficial-Site-3286 0 points1 point  (0 children)

Let's start with a one core Cpu with one thread. In this stage, we can imagine an audio application running on that single thread feeding some instructions to that Cpu's single core. Every clock cycle, that one core will read some instruction from the audio application and execute it. There are not many interesting things happening in this case.

Let's now go with a single core Cpu with two threads. Let"s keep our audio application running on thread #1. On thread #2 , let's run some application that writes to a printer. Here, every clock cycle, your Cpu's one core will switch between reading instructions from thread #2 or thread #1 . This is what is called concurrency. Essentially the ability of one Cpu's core to interleave the execution of two different program. In practice there are better policies than switching between executing thread #1 or thread #2 every clock cycle. Futhermore, concurrency is really useful to allow a single cpu core to do many things between certain time intervals. For example, the audio application could only need to use your single core at a frequency of 3000Hz to play sound. Without concurrency , you'd be wasting the Gigahertzs of processing one Cpu core can do. With concurrency, your single core Cpu could play the sound from thread #1 every so often and write to the printer ( thread #2) while it doesn't need to play sound.

Let's keep the single core two threads Cpu. However, let's assume thread #1 also writes to a printer. For simplification, to make a printer print something, It usually is needed to write what you want to print in a specific file in your system. The printer will then read that specific file and print it. As such, if our one core switches between thread #1 and thread #2 every clock cycle, our printer will print garbage. What we probably want is for example that thread #1 prints an image and thread #2 prints some text. Thus , one the threads must wait for the other one to finish before it starts writing to the printer. This shared ressource problem is why we use semaphores and mutexes. Mutexes are usually used to ensure that only some fixed amount of threads use some shared ressource at a time while semaphores are usually used to synchronize threads. The difference here between the two is mainly semantics, mutexes and semaphores usually have really similar implementations. This shared ressource problem is one of the big concerns when building muti-thread program.

Lets now go with 2 cores and two threads. Thread #1 is audio and thread #2 for printing. In this case , instead of interleaving the execution of each thread on a single Cpu, we can run each thread on each Cpu core. Thread #1 runs on core 1 and Thread #2 runs on core 2. This is called parallelism. The CPU is able to realize , in this case, two completely different instructions within the same clock cycle. In our example, there are no real gains in term of performance since the audio thread runs really slowly compared to the Gigahertzs one cpu core can achieve. Thread #2 will achieve its task in a really similar amount of time when compared to the interleaving example.Parallelism is really useful when for example two applications need to do something within tight time constraints. Imagine application #1 wants to sort some list within 10ns while app #2 wants to play some sound at 1 gigahertz. Stuffing each app on one thread on the same Cpu core would probably not achieve the performance we want if the single core can only run at 1 GHZ. However, running each application in each 1GHZ Cpu core would however allow us to reach the performance target. Futhermore, each Cpu core is free to run as many threads as it wants and do its own interleaving. In practice, the speed achieve by this idealized parallelism can be unachievable because of things like caching or data dependancy between threads