Thread overview
How to have multiple synchronized shared types. Programming in D, page 647
6 days ago
Brother Bill
6 days ago
Brother Bill
6 days ago
Ali Çehreli
5 days ago
Ali Çehreli
6 days ago

The idea is that multiple shared objects use a common lock.

import std.stdio;

void main()
{

}

class BankAccount
{

}

void transferMoney(shared BankAccount from,	shared BankAccount to)
{
	synchronized (from, to)    ← FAILS TO COMPILE.  Doesn't like comma.
	{ // ← correct
		// ...
	}
}

This fails to compile with dmd 2.111.0

c:\dev\D\81 - 90\c86_4f_multiple_synchronized\source\app.d(15): Error: using the result of a comma expression is not allowed
    synchronized (from, to)
                  ^

Is there another way to do this, other than manually, or is this obsolete?

6 days ago

On Sunday, 31 August 2025 at 00:46:50 UTC, Brother Bill wrote:

>

The idea is that multiple shared objects use a common lock.

import std.stdio;

void main()
{

}

class BankAccount
{

}

void transferMoney(shared BankAccount from,	shared BankAccount to)
{
	synchronized (from, to)    ← FAILS TO COMPILE.  Doesn't like comma.
	{ // ← correct
		// ...
	}
}

This fails to compile with dmd 2.111.0

c:\dev\D\81 - 90\c86_4f_multiple_synchronized\source\app.d(15): Error: using the result of a comma expression is not allowed
    synchronized (from, to)
                  ^

Is there another way to do this, other than manually, or is this obsolete?

This syntax was intended to ensure synchronization always happens in a specified order (this text is in The D Programming Langauge book).

However, it was discovered that what actually happens is that only the last value is synchronized on, because this is simply a comma expression!

In a later version of D2, using the result of a comma expression was no longer allowed. This was to eliminate confusing errors (comma expression are seldom needed), and also to make way for using a sequence of expressions to mean a tuple (not yet in the language).

The original feature never worked as intended. That section of the book should be removed.

The correct way to do this is a nested synchronized statement:

synchronized(from) synchronized(to)
{
   ...
}

-Steve

6 days ago

On Sunday, 31 August 2025 at 01:34:18 UTC, Steven Schveighoffer wrote:

>

The correct way to do this is a nested synchronized statement:

synchronized(from) synchronized(to)
{
   ...
}

-Steve

This code compiles:

import std.stdio;

void main()
{

}

class BankAccount
{

}

void transferMoney(shared BankAccount from,	shared BankAccount to)
{
	synchronized (from) synchronized (to)   // ← correct
	{
		// ...
	}
}

6 days ago
On 8/30/25 6:34 PM, Steven Schveighoffer wrote:

> The original feature never worked as intended. That section of the book
> should be removed.
>
> The correct way to do this is a nested synchronized statement:
>
> ```d
> synchronized(from) synchronized(to)
> {
>     ...
> }
> ```
>
> -Steve

That's a recipe for a deadlock though: Imagine the same function is running for two bank accounts (A and B), each sending money to each other.

In one case, 'from' is A, and 'to' is B. In the other case, 'from' is B, and 'to' is A.

One thread locks A and the other locks B, then they both wait for the other forever.

When the language lacks a canonical order for multiple locks, the programmer must come up with a scheme to sort them and attempt to lock in the same order in both threads.

Ali

6 days ago

On Sunday, 31 August 2025 at 03:45:07 UTC, Ali Çehreli wrote:

>

On 8/30/25 6:34 PM, Steven Schveighoffer wrote:

>

The original feature never worked as intended. That section
of the book
should be removed.

The correct way to do this is a nested synchronized statement:

synchronized(from) synchronized(to)
{
    ...
}

That's a recipe for a deadlock though: Imagine the same function is running for two bank accounts (A and B), each sending money to each other.

In one case, 'from' is A, and 'to' is B. In the other case, 'from' is B, and 'to' is A.

One thread locks A and the other locks B, then they both wait for the other forever.

When the language lacks a canonical order for multiple locks, the programmer must come up with a scheme to sort them and attempt to lock in the same order in both threads.

D has never supported this.

From the book:

>

Note: This feature is not supported by dmd 2.098.1.

This should read:

>

Note: this feature has never been implemented and before DMD 2.098.1 this syntax would compile and do the wrong thing.

Which is why I recommend removing the whole discussion.

If you want to ensure some order of locking you need to do it manually. Even before 2.098.1

-Steve

5 days ago
On 8/31/25 3:52 AM, Steven Schveighoffer wrote:

>  From the book:
>
>> Note: This feature is not supported by dmd 2.098.1.

What I meant there was "not yet; maybe in the future."

> Which is why I recommend removing the whole discussion.

Fair.

> If you want to ensure some order of locking you need to do it manually.
> Even before 2.098.1

Ensuring order of locking is not something that the programmer *may* want. The hardcoded order of two synchronized blocks is a program bug because it leads to a deadlock.

Ali