互斥量应该存储在 main 中还是对象中?
Should mutexes be stored in main or in the object?
以 C 中的对象为例:
/* object.h */
typedef struct Object Object;
Object* createObject();
void freeObject(Object* object);
int getObjectNumber(Object* object);
void incrementObjectNumber(Object* object);
这是一个非常简单的不透明类型,它存储一个数字并可以递增它。
为了让我的代码线程安全,我有两个选择。第一个是在 Object:
中存储一个互斥量
void
func(Object* object)
{
incrementObject(object);
}
int
main()
{
Object* object = createObject();
Thread thread1 = startThread(func, object);
Thread thread2 = startThread(func, object);
waitThread(thread1);
waitThread(thread2);
freeObject(object);
}
第二种是在main中存放一个互斥体:
void
func(Object* object, Mutex mutex)
{
lockMutex(mutex);
incrementObject(object);
unlockMutex(mutex);
}
int
main()
{
Object* object = createObject();
Mutex mutex;
Thread thread1 = startThread(func, object, mutex);
Thread thread2 = startThread(func, object, mutex);
waitThread(thread1);
waitThread(thread2);
freeObject(object);
}
如果只有一个对象,哪一个是更好的做法?
这取决于你想达到什么目的。有时您需要内部线程安全,有时需要外部线程安全。
通常,决定取决于外部用户是否需要组合操作。比如说,他们希望 f()
和 g()
都自动发生。如果您将互斥锁隐藏在 Object
中,如果不自己管理另一个互斥锁,他们将无法实现这一点(然后您必须处理正在使用的多个锁,这可能导致死锁等)。
无论是一个对象还是多个对象,最好将互斥量与不透明对象一起存储。首先,互斥锁和它保护的数据属于一体。而且,线程安全需要由您的 "ADT" 而不是调用者来处理。只能通过 setters/getters 访问对象,这将在内部处理线程安全。在这种情况下 incrementObject
.
这样你就可以声明你的整个库是线程安全的,它会照顾好自己而不是把责任推给别人。您的第一个示例更清晰 API,而第二个示例要求调用者将互斥锁拖到用户定义的回调中,这不是一个干净的解决方案。
以 C 中的对象为例:
/* object.h */
typedef struct Object Object;
Object* createObject();
void freeObject(Object* object);
int getObjectNumber(Object* object);
void incrementObjectNumber(Object* object);
这是一个非常简单的不透明类型,它存储一个数字并可以递增它。
为了让我的代码线程安全,我有两个选择。第一个是在 Object:
中存储一个互斥量void
func(Object* object)
{
incrementObject(object);
}
int
main()
{
Object* object = createObject();
Thread thread1 = startThread(func, object);
Thread thread2 = startThread(func, object);
waitThread(thread1);
waitThread(thread2);
freeObject(object);
}
第二种是在main中存放一个互斥体:
void
func(Object* object, Mutex mutex)
{
lockMutex(mutex);
incrementObject(object);
unlockMutex(mutex);
}
int
main()
{
Object* object = createObject();
Mutex mutex;
Thread thread1 = startThread(func, object, mutex);
Thread thread2 = startThread(func, object, mutex);
waitThread(thread1);
waitThread(thread2);
freeObject(object);
}
如果只有一个对象,哪一个是更好的做法?
这取决于你想达到什么目的。有时您需要内部线程安全,有时需要外部线程安全。
通常,决定取决于外部用户是否需要组合操作。比如说,他们希望 f()
和 g()
都自动发生。如果您将互斥锁隐藏在 Object
中,如果不自己管理另一个互斥锁,他们将无法实现这一点(然后您必须处理正在使用的多个锁,这可能导致死锁等)。
无论是一个对象还是多个对象,最好将互斥量与不透明对象一起存储。首先,互斥锁和它保护的数据属于一体。而且,线程安全需要由您的 "ADT" 而不是调用者来处理。只能通过 setters/getters 访问对象,这将在内部处理线程安全。在这种情况下 incrementObject
.
这样你就可以声明你的整个库是线程安全的,它会照顾好自己而不是把责任推给别人。您的第一个示例更清晰 API,而第二个示例要求调用者将互斥锁拖到用户定义的回调中,这不是一个干净的解决方案。