Pascal does not really have great support for parallel programming. It has threads and synchronization mechanisms (like critcial sections and events) but thats the bare minimum. Thats a bit like saying "here you have some iron, copper, rubber, and other raw materials, go and build a car". Possible but tedious.
There are languages out there that incorporate parallel programming into their language design. One such example would be Erlang, which was specifically designed by Erricson for high performance networking code, and today around 90% of all internet traffic is handled by erlang code somehwere along the way. It is also commonly used in server software that requires a high uptime and managing many users like Amazons SimpleDB powering ther AWS EC2 systems or the Facebook and WhatApp Chat servers.
And I think it is always a great case study to look at what makes erlang so successful for parallel programming, and how this is lacking in Pascal.
So beginning with the first reason, Erlang is VM based, which completely abstracts it from the underlying OS and hardware. Pascal threads are OS threads, while Erlang threads are VM threads. The VM controlls the utilization of the hardware, and maps the software threads to actual OS level threads. This means you are limited by the OS and hardware. On linux you can only have a certain number of threads, spawning and killing threads is slow, and the scheduler will always take a certain amount of time due to context switches. Erlang VM threads on the other hand are really lightweight, can be spawned and released in no time and the scheduler is blazing fast and there are no context switches involved.
This allows you to spawn millions of Erlang threads on pretty much any hardware and OS really efficiently. People often associate VMs with being slow, this is probably due to the garbage collection in Java or .Net, but this is not necessarily the case. As stated above, erlang was developed for creating router firmware and today erlang is capable of handling up to terrabytes of data each second.
Also this is completely hardware independent, so your Erlang code will work the same on a single cpu microcontroller or on a large computing cluster.
For an example, if you write a server that handles tens-hundreds of thousands of TCP streams, in Erlang, each of those streams would have it's own thread. With standard OS threads like with Pascal, this wouldn't work, and what you usually do is to have a few hundred threads, each serving a few thousand streams (using polling to access those streams non blockingly).
So while this is theoretically possible to manage in Pascal, the effort involved is much greater.
This is also why other languages like C# introduced their Task system with the thread manager that does exactly the same, chopping of your code into tasks, which can then be software scheduled transparently by the VM to the real os threads.
The second reason is probably the most obvious, Erlang is a functional language, which means it is side effect free. This means each piece of Erlang code is completely independent from each other, all data structures are immutable and there is no such thing as shared memory (in fact in functional programming there isn't even such thing as a concept of memory). Therefore you don't need synchronization mechanisms. The only way for data to be communicated between parts of the program is through well defined communication channels on a language level. This allows first for a formal method of ananlysis, as all data flows can be mapped through these well defined channels. This makes also both optimisation as well as distribution much easier. As you only have these channels, it doesn't matter how this data is transmitted, it could be send through a message queue in memory, managed by the VM, it could be through IPC or even through network to connect completely different machines with one logical erlang program.
Also by the fact that the memory is immutable, it also means that you can do lazy copies. If a number of threads use the same data (e.g. some lookup table), but as it is immutable no one can change it, you can simply let all of them access the same data, without having to create a copy for each object.
Immutability is a concept that is also coming more and more to other languages like Java, C#, Python, C++ or Javascript, have concepts of immutable datatypes, exactly for that reason. Immutability makes a lot of things easier, and with language level support for it, the compiler can also highly optimize such structures.
In pascal this is actually kinda archivable, by using forks that communicate through pipes. This separates the memory of each of the processes, but fork will only copy memory laziely, meaning shared pages that are not altered will be shared in memory. This is great for separating tasks and allows for structured communication between those tasks, where the OS takes the job of all the hard threading and synchronization problems. I would highly advise doing this, but the only problem here is, that this is extremely inefficient. Spawning processes is really slow and takes a lot of resources. So while this is a very great solution that allows for creating extremely clean seperation of tasks, it is also not scalable.
So I recommend using this when possible, but scaling it to thousands let alone millions of processes will probably not end well.
Also Pascal does not really have much support for immutable Datatypes, there are pretty much None in the RTL, FCL and RTL, and also on a language level there is no real way to write immutable datatypes (like final in java or const in C++), so there is no way for the compiler to optimise for them.
If you want to do this scalable in a large scale system, you need to build your own scalable message queues and build your tasks/threads in a way that you don't touch shared memory, or if you do, you need to make sure to use synchronization or that it is immutable (which again is not supported on a language level)
The last big reason is the unoffical slogan of Erlang: "let it fail". This referrs to the error management of erlang. Each task is generally supervised by another task so for example with a server, you might have your server task, which spawns a new task for each incomming connection, here the server task is the supervisor of the connection tasks. If you have an error in one of the tasks, the task will simply fail and be stopped, and the supervisor will be notified. The supervisor can than choose to react if it wants to ignore it, handle it, or fail itself. For example in telephony systems, where erlang was also heaviely used, when there was an error during a call, the switch would simply drop the connection and ignore the error. The humans trying to phone would simply try to call again (or maybe even the phone software would do this automatically) so the connection switch does not need to bother trying to fix the error, it will probably go away on a new call. If to many errors occur, it can try to resolve this, or the switch completely fails, the rest of the telephony network reroutes all of the incomming connections and an engineer can look at what went wrong.
Pascal has exceptions, which can be used for something similar. In fact, for my STAX I've basically rebuilt that system (even before I knew it from Erlang), but trust me, this is really tedious. So again, something you can do but a lot more effort as you basically have to build everything yourself.
All of this makes Erlang a really great language for parallel systems. Erricson actually measured a decrease in development time of a factor 10-25 and a reduction in code size of 2-10 compared to their previous development models (mainly with imperative languages like C which have similar properties to pascal with respect to parallel programming).
So to summarize, you can write scalable parallel programs in Pascal, but Pascal only gives you the bare bones and it is not comparable to any language that is designed for this and has this built in on a language level, so you will have much more work to archive similar results.