affq19
ChatRoom in Elixir using Mutex and Threads
Hi! I’ve been studying concurrency models with elixir. Now, I want to develop a ChatRoom, where users can Join, post messages, and disconnect themselves using threads and mutex in elixir. So far I have developed the model for entering new users and disconnect them. However, I have put some “prints” to see how its working, but they are not showing when I run the program. This is the code,
defmodule MyMutex do
@mutex :free
def lock(:free) do
{:ok, :locked}
end
def lock(:locked) do
{:error, :already_locked}
end
def unlock(:locked) do
:ok
end
def unlock(:free) do
{:error, :not_locked}
end
end
defmodule Chat do
defstruct users: [], messages: [], mutex: MyMutex
def start_link() do
{:ok, pid} = Task.start_link(fn -> action(%__MODULE__{}) end)
end
defp action(chat) do
receive do
{:join, :user} ->
chat = new_user(chat, :user)
action(chat)
#{:post, user} ->
# chat = post_message(chat, user)
# action(chat)
{:disconnect, user} ->
chat = disconnect_user(chat, user)
action(chat)
{:users_chat} ->
post_all_users(chat)
action(chat)
end
end
defp post_all_users(chat) do
Enum.each(chat.users, fn user ->
"User:"
end)
end
defp post_message_to_all(chat, message) do
Enum.each(chat.users, fn user ->
IO.puts("Message from server: #{message} (Sent to: #{user})")
end)
end
defp new_user(chat ,user) do
{:ok, mutex} = MyMutex.lock(chat.mutex)
updated_chat = %{ chat | users: chat.users ++ [user], mutex: mutex }
IO.puts("Entering the chat: #{user}")
MyMutex.unlock(mutex)
post_message_to_all(updated_chat, "#{user} has joined the chat.")
updated_chat
end
defp disconnect_user(chat, user) do
{:ok, mutex} = MyMutex.lock(chat.mutex)
chat = %{chat | users: List.delete(chat.users, user),
mutex: mutex}
IO.puts("The user #{user} has leaved the chat")
MyMutex.lock(mutex)
chat
end
end
Thanks in Advice ![]()
Most Liked
dimitarvp
What was your education source that claimed you need mutexes in Elixir? ![]()
You don’t need them here.
kokolegorille
arijoon
I have to agree with other posters regarding mutex. General usecase for a mutex is to lock a shared resource when multiple threads are writing to it. In erlang we have processes which do not share resources. If you wish to share something (for example the chat messages), you can create a new process which holds this information and read/write to it by sending messages to that process. Since the process will only action one message at a time, no mutex will be required
dimitarvp
Do you know of GenServer?
voughtdq
@affq19 I made some revisions to your code to get it to work. There are commit messages that you can look at to understand why the changes were made. I’ve also added a simple test module to test it. It can be invoked from iex like this:
c("chat.ex")
Test.run()
As has been discussed, the mutex really isn’t necessary here and implementing this using either Process.spawn/1,3 or as a GenServer is the correct way to do it. You should be able to safely remove the mutex code without it affecting anything and it might be a good first step to make the code more Elixirish.







