question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Please don't deprecate release() function

See original GitHub issue

With great power comes great responsibility…says Batman I think 😉

I get it, runExclusive ensures you don’t screw things up and not unlock the thread, but sometimes you can’t set things up with a nice try / catch loop and you really need to use withTimeout to ensure it doesn’t lock the application.

Here is an example from React Native that I made as a workaround for this Expo issue:


import React, {useCallback, useRef, useState} from "react";
import {MutexInterface, withTimeout, Mutex} from "async-mutex";
import {Video} from "expo-av";
import {Asset} from "expo-media-library";

type IVideoInfo = Pick<Asset, "width" | "height" | "duration">;

const useVideoInfo = () => {
  const [uri, setUri] = useState<string>();
  // const mutexRef      = useRef<MutexInterface>(withTimeout(new Mutex(), 4000));
  // withTimeout didn't really seem to be working...so we just set a timeout
  const mutexRef      = useRef<MutexInterface>(new Mutex());
  const videoInfoRef  = useRef<IVideoInfo>();

  const getVideoInfo = useCallback(
    async (uri: string) => {
      mutexRef.current.release();
      videoInfoRef.current = undefined;

      await mutexRef.current.acquire();
      setTimeout(() => mutexRef.current.release(), 5000);
      setUri(uri);

      await mutexRef.current.waitForUnlock();
      if (!videoInfoRef.current) {
        throw(`Could not extract the video info from ${uri}`)
      }
      return videoInfoRef.current;
    },
    [],
  );

  const VideoInfoExtractor = useCallback(
    () => <Video
      style={{width: 1, height: 1, opacity: 1}}
      source={{ uri }}
      onReadyForDisplay={event => {
        if (event.status?.isLoaded) {
          const { width, height } = event.naturalSize;
          videoInfoRef.current = {width, height, duration: event.status.durationMillis / 1000};
          mutexRef.current.release();
        }
      }}
    />,
    [uri],
  );

  return {
    VideoInfoExtractor,
    getVideoInfo,
  };
};

export {
  useVideoInfo,
  IVideoInfo,
};

Rewriting this somehow with runExclusive would basically fly in the face of what I’m trying to do here which is wait for one thing to wait for another.

Can we keep the acquire/release paradigm into the future? 🙏

PS. For some reason the withTimeout wrapper didn’t work for me…so I had to use setTimeout…maybe I’m doing something wrong?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:7
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
DirtyHairycommented, Jan 7, 2022

It continue to be surprised by the way this library is used in projects 😏

A bit of background on why I have been planning to remove Mutex::release (the same holds true for Semaphore). This library originally was intended for limiting concurrency in critical sections of code. To that end, the original API did not contain Mutex::release; instead, Mutex::acquire returns a dedicated release callback that is scoped to the individual lock acquired by acquire. This has the benefit of being idempotent: multiple calls will have no effect, even if the mutex has been locked again. In order to have a RAII type approach to unlocking, I also added runExclusive from the start.

I only added Mutex::release when people started requesting it in order to avoid managing the individual releasers returned by subsequent calls to acquire. When I added it I was in a hurry, and I only later realized that this use case is much better served by runExclusive. So, I decided to deprecate and remove it again.

However, judging from your example (and from other requests for keeping this function) it seems that people are now also using the library now to notify waiters when a task has completed, and this cannot be refactored to use runExclusive (and scoped releasers are awkward in this case). I guess I can’t really go back and remove that function again. So, worry not, I’ll keep it (and probably also make it work properly for nontrivial semaphores) 😏 I’ll remove the annotation and adapt the documentation when I next update the library.

As for using the semaphore as a condition variable: I would much rather add an async queue to the library. You would call await queue.next() to wait for the next value to be pushed into the queue, and calling queue.push(...) would push the next value into the queue. New values would be distributed to waiters in a first come, first served fashion. I think this would probably cover all use cases that I have seen where mutex / semaphore are used for notification rather than for limiting concurrency. Would that fit your shoe?

3reactions
cscheidcommented, Dec 10, 2021

+1 please please don’t deprecate release 😃

release (to use, um, boomer language, V) before acquire (P) on a semaphore initialized to zero can be used to get (effectively) condition variables, which is pretty nice to have since async-mutex doesn’t implement those directly.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Deprecate functions and arguments — deprecate_soft • lifecycle
A string giving the version when the behaviour was deprecated. what. A string describing what is deprecated: Deprecate a whole function with "foo()"...
Read more >
How and When to Deprecate APIs - Oracle Help Center
Java provides a way to express deprecation because, as a class evolves, its API (application programming interface) inevitably changes: methods are renamed for ......
Read more >
Deprecating changes for 1 release instead of removing #383
@trigger_error('XXX() is deprecated since version 2.8 and will be removed in 3.0. Use XXX instead.', E_USER_DEPRECATED);.
Read more >
How to mark a method as obsolete or deprecated?
The shortest way is by adding the ObsoleteAttribute as an attribute to the method. Make sure to include an appropriate explanation: [Obsolete("Method1 is ......
Read more >
What is deprecated in IT? - TechTarget
In information technology (IT), deprecation means that although something is available or allowed, it is not recommended or that -- in the case...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found