Skip to content

Commit

Permalink
init concurrency primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
bcpeinhardt committed Feb 24, 2024
1 parent 6864dc5 commit 369a45b
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 0 deletions.
23 changes: 23 additions & 0 deletions concurrency_primatives/.github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: test

on:
push:
branches:
- master
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: erlef/setup-beam@v1
with:
otp-version: "26.0.2"
gleam-version: "0.34.1"
rebar3-version: "3"
# elixir-version: "1.15.4"
- run: gleam deps download
- run: gleam test
- run: gleam format --check src test
4 changes: 4 additions & 0 deletions concurrency_primatives/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.beam
*.ez
/build
erl_crash.dump
3 changes: 3 additions & 0 deletions concurrency_primatives/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# concurrency_primatives


20 changes: 20 additions & 0 deletions concurrency_primatives/gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name = "concurrency_primatives"
version = "1.0.0"

# Fill out these fields if you intend to generate HTML documentation or publish
# your project to the Hex package manager.
#
# description = ""
# licences = ["Apache-2.0"]
# repository = { type = "github", user = "username", repo = "project" }
# links = [{ title = "Website", href = "https://gleam.run" }]
#
# For a full reference of all the available options, you can have a look at
# https://gleam.run/writing-gleam/gleam-toml/.

[dependencies]
gleam_stdlib = "~> 0.34 or ~> 1.0"
gleam_erlang = "~> 0.24"

[dev-dependencies]
gleeunit = "~> 1.0"
13 changes: 13 additions & 0 deletions concurrency_primatives/manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This file was generated by Gleam
# You typically do not need to edit this file

packages = [
{ name = "gleam_erlang", version = "0.24.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "26BDB52E61889F56A291CB34167315780EE4AA20961917314446542C90D1C1A0" },
{ name = "gleam_stdlib", version = "0.35.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5443EEB74708454B65650FEBBB1EF5175057D1DEC62AEA9D7C6D96F41DA79152" },
{ name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" },
]

[requirements]
gleam_erlang = { version = "~> 0.24"}
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }
64 changes: 64 additions & 0 deletions concurrency_primatives/src/concurrency_primatives.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import gleam/io
import gleam/erlang/process
import gleam/string

pub fn main() {
// A "process" in gleam is a lightweight, concurrent unit of execution.
// Other languages might call this a "coroutine" or a "green thread".
// Every process has a unique identifier call a "process id" or "pid"
// for short. These can be used to monitor or kill processes.
let pid = process.self()
io.println("Current process id: " <> string.inspect(pid))

// We can spawn a new process using the `start` function. It takes two
// arguments: a function to run in the new process, and a boolean indicating
// whether the new process should be "linked" to the current process.
// "Linked" processes fail together (one crashing causes the other to crash).
// The link is bidirectional.
process.start(
fn() {
let pid = process.self()
io.println("New process id: " <> string.inspect(pid))
},
True,
)

// Doing work in other processes is well and good, but if we want to
// send messages between different processes, we need a `Subject`.
// The subject is a combination of a unique identifier and the process id
// of the process that created it.
let subj = process.new_subject()

// Once we have a subject, we can use it to send messages to the owner
// process from any other process.
process.start(fn() { process.send(subj, "hello, world") }, True)

// The `receive` function is used to listen for messages sent to the current process.
let assert Ok("hello, world") = process.receive(subj, 1000)

// Note: If you've ever dabbled in Erlang/Elixir concurrency tutorials, you may be used
// to sending messages to a process id directly. In Gleam, we use subjects, which
// have a few advantadges over process ids:
// - They are generic over the message type, so we get type safe messages.
// - You can have multiple per process. You can use multiple subjects to
// decouple the order in which messages are sent from the order in which they
// are received.

// Lets make a second subject, also owned by the current process.
let subj2 = process.new_subject()

// Here we spawn a new process, and use the subjects to send messages
// back to our current process.
process.start(
fn() {
process.send(subj, "goodbye, mars")
process.send(subj2, "whats up, pluto")
},
True,
)

// We can use each subject to receive the specific message we care about,
// and we don't have to worry about the order in which the messages are sent.
let assert Ok("whats up, pluto") = process.receive(subj2, 1000)
let assert Ok("goodbye, mars") = process.receive(subj, 1000)
}
12 changes: 12 additions & 0 deletions concurrency_primatives/test/concurrency_primatives_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import gleeunit
import gleeunit/should

pub fn main() {
gleeunit.main()
}

// gleeunit test functions end in `_test`
pub fn hello_world_test() {
1
|> should.equal(1)
}

0 comments on commit 369a45b

Please sign in to comment.