c - C中读写锁的线程安全销毁

标签 c multithreading posix destroy readwritelock

我正在尝试使用 POSIX 信号量在 C 中编写一个线程安全的读写锁。可以看到源码的当前状态here . 我关注了this创建读者首选锁。

问题是我想处理调用 rwl_destroy() 时可能处于的任何可能状态的锁的销毁。

如果调用 destroy 并且没有其他线程在锁上,那么它将锁定 wrt(由 writers 使用)以防止任何其他线程访问锁保护的数据。接下来 destroy 函数应该销毁信号量并释放为 ReadWriteLock 结构分配的内存。但是如果另一个线程正在等待锁呢?根据文档,该线程将处于未定义状态。

这就是我试图避免的,以便使锁更易于使用。

编辑:

当前代码是:

typedef struct ReadWriteLock
{
sem_t wrt;
sem_t mtx;
sem_t delFlag;
int readcount;
int active;
}ReadWriteLock;

//forward declaration
/* This function is used to take the state of the lock.
 * Return values:
 *      [*] 1 is returned when the lock is alive.
 *      [*] 0 is returned when the lock is marked for delete.
 *      [*] -1 is returned if an error was encountered.
 */
int isActive(ReadWriteLock*);

int rwl_init(ReadWriteLock* lock)
{
lock = malloc(sizeof(ReadWriteLock));
if (lock == NULL)
{
    perror("rwl_init - could not allocate memory for lock\n");
    return -1;
}
if (sem_init(&(lock->wrt), 0, 1) == -1)
{
    perror("rwl_init - could not allocate wrt semaphore\n");
    free(lock);
    lock = NULL;
    return -1;
}
if (sem_init(&(lock->mtx), 0, 1) == -1)
{
    perror("rwl_init - could not allocate mtx semaphore\n");
    sem_destroy(&(lock->wrt));
    free(lock);
    lock = NULL;
    return -1;
}
if (sem_init(&(lock->delFlag), 0 , 1) == -1)
{
    perror("rwl_init - could not allocate delFlag semaphore\n");
    sem_destroy(&(lock->wrt));
    sem_destroy(&(lock->mtx));
    free(lock);
    lock = NULL;
    return -1;
}

lock->readcount = 0;
lock->active = 1;
return 0;
}

int rwl_destroy(ReadWriteLock* lock)
{
errno = 0;
if (sem_trywait(&(lock->wrt)) == -1)
    perror("rwl_destroy - trywait on wrt failed.");
if ( errno == EAGAIN)
    perror("rwl_destroy - wrt is locked, undefined behaviour.");

errno = 0;
if (sem_trywait(&(lock->mtx)) == -1)
    perror("rwl_destroy - trywait on mtx failed.");
if ( errno == EAGAIN)
    perror("rwl_destroy - mtx is locked, undefined behaviour.");

if (sem_destroy(&(lock->wrt)) == -1)
    perror("rwl_destroy - destroy wrt failed");
if (sem_destroy(&(lock->mtx)) == -1)
    perror("rwl_destroy - destroy mtx failed");
if (sem_destroy(&(lock->delFlag)) == -1)
    perror("rwl_destroy - destroy delFlag failed");

free(lock);
lock = NULL;
return 0;
}

int isActive(ReadWriteLock* lock)
{
errno = 0;
if (sem_trywait(&(lock->delFlag)) == -1)
{
    perror("isActive - trywait on delFlag failed.");
    return -1;
}
if ( errno == EAGAIN)
{//delFlag is down, lock is marked for delete
    perror("isActive - tried to lock but ReadWriteLock was marked for delete");
    return 0;
}
return 1;
}

我还有这些功能:

int rwl_writeLock(ReadWriteLock*);

int rwl_writeUnlock(ReadWriteLock*);

int rwl_readLock(ReadWriteLock*);

int rwl_readUnlock(ReadWriteLock*);

所以我的问题是如何更改这些函数以避免出现我上面描述的未定义状态。在尝试销毁 ReadWriteLock 之前,是否有可能或此代码的用户应该负责释放所有锁?

isActive() 函数和delFlag 信号量目前没有使用,它们是我尝试解决问题时创建的。

最佳答案

您应该实现 ReadWriteLock 实例的“处置”状态(“事件”字段看起来很合适,但您不使用它,为什么?)。

在 sem_wait() 调用之前和之后,在 rwl_writeLock/rwl_readLock 中检查两次。这个技巧被称为“双重检查锁定模式”。如果你在进入sem_wait之前发现你的Lock被删除了,就离开这个函数。 如果你进入sem_wait后发现你的Lock被删除了,马上做sem_post然后离开。

在您的 destroy() 例程中,设置 active=0,然后将 sem_post 设置为两个信号量(如果 sem_post 失败,请不要打扰)。如果之后您仍然需要 sem_destroy,请稍作休眠(以便所有读者和作者都有时间接收信号)并执行 sem_destroy。

附言如果您确定不再使用信号量,则实际上无需调用 sem_destroy。

关于c - C中读写锁的线程安全销毁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28049475/

相关文章:

c - 不明白CII书第108页中的函数List_list

c - 在不同的 "platforms"之间移植 C 代码

c - C 中的 switch 语句和 getopt() 函数

django - Django 持久数据库连接线程安全如何?

c# - 应用程序运行,但最终以 SIGSEGV 或 NullReferenceException 结束

c - 从 .txt 文件中读取并将特定行存储在字符串中

java - 使用 iMap 的 Hazelcast 分布式锁

multithreading - Clojure并行计算数组

c - 初始化返回变量时,读取缓冲区清零

python - 如何读取到达 PTY 主端的数据副本?