POSIX セマフォを使用して C でスレッドセーフな読み書きロックを作成しようとしています。ソース コードの現在の状態は、こちらで確認できます。これに従って、読者優先のロックを作成しました。
問題は、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 セマフォは現在使用されていません。問題を解決するために作成されました。