互斥锁,自动阻止对数据结构的写入?

huangapple go评论76阅读模式
英文:

Mutex locks that automatically prevent writing to data structure?

问题

有没有办法明确地为C结构或其他数据结构定义互斥锁,以便在尝试在未先锁定的情况下写入数据结构时引发异常?

英文:

Is there a way to explicitly define a mutex lock for a C struct or other data structure such that an exception would be thrown if I tried writing to the data structure without locking first?

答案1

得分: 1

簡而言之,不行。沒有硬件機制可用於實現這一點。

硬件分頁功能(虛擬內存)可以設置為在寫入地址時觸發陷阱,導致將SIGSEGV或SIGBUS交付給進程。然而,這將是一個無條件的陷阱;不僅僅在互斥體未被持有時。您將為對對象的每次寫入支付陷阱的代價(這相當慢),包括那些正常的寫入,並且您必須在信號處理程序中測試互斥體。

此外,這的最小粒度是一個頁面(幾KB),因此您要么將每個對象放在自己的頁面上並浪費大量內存,要么忍受無關的訪問導致虛假陷阱的情況,您的處理程序必須忽略,並使程序減慢速度很多。

某些機器具有用於調試的“硬件觀察點”,可以在特定地址的訪問時觸發,具有字節或字粒度。但這同樣是無條件的,而且硬件通常僅提供一個較小的固定數量(一位數),在至少某些情況下,使用它們會減慢整個程序的速度。(但在調試器中使用它們可能很方便;例如通過gdb中的hwatch命令。gdb還允許您設置調試器將在觀察點的每次命中上測試的條件,只有在條件為真時才停止程序,因此您可以將您的鎖測試放在那裡。)

如果對對象的所有訪問都是通過特定的getter/setter函數進行的,那當然可以在這些函數中放入檢查代碼。但它對於直接訪問對象的有缺陷的代碼或者getter/setter本身有缺陷並跳過測試的情況無濟於事。 (前一種情況在像C++這樣的語言中有所幫助,可以使對象的數據private,但在C中,這取決於您自己的紀律。)無論如何,如果您選擇這種路線,通常您會讓getter/setter首先處理鎖,這樣對於程序的其餘部分來說就不成問題了。

查找此類錯誤的更有效方法是使用像ThreadSanitizer這樣的工具,它包含在gcc和clang中。它會對程序進行儀器化,以識別由於不足的鎖定而可能出現的數據競爭。ThreadSan會對性能產生相當大的影響,所以它可能不適合在生產中使用,但對於開發和測試來說是一個不錯的主意。

英文:

In short, no. There is no hardware mechanism that could be used to implement this.

The hardware paging features (virtual memory) can be set to cause a trap on any write to an address, resulting in a SIGSEGV or SIGBUS being delivered to the process. However, this would be an unconditional trap; not only if the mutex is not held. You'd pay the price of the trap (which is quite slow) on every write to the object, including those that are just fine, and you'd have to test the mutex in your signal handler.

Also, the minimum granularity of this is one page (several KB) and so either you have to put every object on its own page and waste a lot of memory, or else put up with unrelated accesses causing spurious traps that your handler must ignore, and which slow down your program by a lot.

Some machines have "hardware watchpoints" for debugging, that can trap on access to a specific address with byte or word granularity. But this is likewise unconditional, and the hardware normally provides only a small fixed number of them (single digits), and in at least some cases, using them at all slows down the entire program. (It could be handy to use in your debugger, though; e.g. via the hwatch command in gdb. gdb will also let you set a condition that the debugger will test on every hit of the watchpoint, and only stop the program if the condition is true, so you could put your lock test there.)

If all accesses to the object are through specific getter/setter functions, then of course you can put checking code in those functions. But it won't help with buggy code that accesses the object directly, or if the getter/setter itself is buggy and skips the test. (The former case is helped by languages like C++ that could make the object's data private, but in C it's up to your own discipline.) Anyway, if you're going that route, usually you would have the getter/setter handle the locking in the first place, so that it becomes a non-issue for the rest of the program.

A more effective way to find such bugs is with a tool like ThreadSanitizer, which is included in both gcc and clang. It instruments the program to identify data races such as could arise from inadequate locking. ThreadSan does have a substantial performance penalty, so it's probably not suitable for use in production, but would be a good idea for development and testing.

答案2

得分: 0

> 有没有一种明确定义 C 结构或其他数据结构的互斥锁的方法,以便在未先锁定的情况下尝试写入数据结构时会引发异常?

如果没有使用特定于操作系统的技巧(例如,纯粹的 C 而没有任何 POSIX 等),我表示怀疑。

使用特定于操作系统的技巧,你可以默认情况下使数据无法访问,然后在获取互斥锁时将数据映射到一个“随机”的虚拟地址,并返回数据的指针(并在释放互斥锁时取消映射数据);这样,其他线程在未获取锁的情况下访问数据的机会几乎为零(因为它们不会知道数据的有效虚拟地址);因此,如果尝试在未获取互斥锁的情况下访问它,很可能会触发 SIGSEGV

对于类Unix操作系统,你可能需要查看 shmget()shmat()shmdt()

对于Windows,可能是 CreateFileMapping()MapViewOfFile()UnmapViewOfFile()

英文:

> Is there a way to explicitly define a mutex lock for a C struct or other data structure such that an exception would be thrown if I tried writing to the data structure without locking first?

Without OS specific tricks (e.g. just pure C without any POSIX or anything) I doubt it.

With OS specific tricks you could make the data inaccessible by default, then when the mutex is acquired map the data at a "random" virtual address and return a pointer to the data (and unmap the data when the mutex is released); so that the chance of any other thread accessing the data without acquiring the lock is almost zero (as it wouldn't know a valid virtual address for the data); and so that it's very likely that a thread will get SIGSEGV if it tries to access it without acquiring the mutex.

For Unix-like operating systems, you might want to look at shmget(), shmat() and shmdt() for this.

For Windows it might be CreateFileMapping(), MapViewOfFile() and UnmapViewOfFile().

huangapple
  • 本文由 发表于 2023年2月26日 21:34:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75572338.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定