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

时间:2015-01-20 15:44:33

标签: c multithreading posix destroy readwritelock

我试图使用POSIX信号量在C中编写一个线程安全的读写锁。您可以看到源代码here的当前状态。 我按照this创建了一个读者偏好的锁。

问题是我希望在调用rwl_destroy()时处理锁的破坏,以防止它可能出现的任何状态。

如果调用destroy并且锁上没有其他线程,那么它将锁定wrt(由编写者使用)以防止任何其他线程访问由锁保护的数据。接下来,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信号量,它们是在我尝试解决问题时制作的。

1 个答案:

答案 0 :(得分:0)

你应该实施"处置"您的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。

P.S。如果你确定不再使用信号量,你实际上不需要调用sem_destroy。

相关问题