【问题标题】:Using Windows slim read/write lock使用 Windows slim 读/写锁
【发布时间】:2011-10-07 12:18:04
【问题描述】:
/*language C code*/

#include "windows.h"

typedef struct object_s
{
    SRWLOCK lock;
    int data;
} object_t, *object_p; /*own and pointer type*/

void thread(object_p x)
{
    AcquireSRWLockExclusive(&x->lock);
    //...do something that could probably change x->data value to 0
    if(x->data==0)
        free(x);
    else
        ReleaseSRWLockExclusive(&x->lock);
}

void main()
{
    int i;
    object_p object=(object_p)malloc(sizeof(object_t));

    InitializeSRWLock(&object->lock);

    for(i=0;i<3;i++)
     CreateThread(0,0,thread,object,0);
}

正如您在上面的代码中所知道的,我必须完成的是让一个线程有条件地释放其他两个可能阻塞的对象。上面的代码显然是有缺陷的,因为如果对象与锁一起被释放,所有阻塞线程只会给我们错误。

下面的解决方案

/*language C code*/

#include "windows.h"

typedef struct object_s
{
    /*change: move lock to stack in main()*/
    int data;
} object_t, *object_p; /*own and pointer type*/

void thread(void * x)
{
    struct {
    PSRWLOCK l;
    object_p o;
    } * _x=x;
    AcquireSRWLockExclusive(_x->l);
    //...do something that could probably change x->data value to 0
    if(_x->o->data==0)
        free(_x->o);
    ReleaseSRWLockExclusive(&x->lock);
}

void main()
{
    int i;
    SRWLOCK lock; /*lock over here*/
    object_p object=(object_p)malloc(sizeof(object_t));

    InitializeSRWLock(&lock);

    /*pack for thread context*/
    struct
    {
        PSRWLOCK l;
        object_p o;
    } context={&lock, object};

    for(i=0;i<3;i++)
     CreateThread(0,0,thread,&context,0);
}

在这种情况下有效,但在我的最终项目中不适用,因为实际上有一个动态的对象链接列表。通过应用这个解决方案,这意味着必须有一个相应的锁列表,每个锁对应一个对象,此外,当某个对象被释放时,它的锁必须同时被释放。与第一个代码部分相比,没有什么新东西。

现在我想知道是否有替代解决方案。非常感谢!

【问题讨论】:

    标签: c windows multithreading winapi asynchronous


    【解决方案1】:

    解决办法是不要把锁和数据一起分配。我建议您将数据移出该结构并用指向数据的指针替换它。然后,您的链表可以先释放数据,然后再释放节点,没有任何问题。这是一些伪代码:

    typedef struct 
    {
      lock_t lock;
      int*   data_ptr;
    } something_t;
    
    void init_something (something_t* thing, ...)
    {
      thing->lock = init_lock();
      thing->data_ptr = malloc(...);  // whatever the data is supposed to be
    }
    
    void free_something (somthing_t* thing)
    {
      lock(thing->lock);
        free(thing->data_ptr);
        thing->data_ptr = NULL;
      unlock(thing->lock);
    }
    
    ...
    
    void linked_list_delete_node (...)
    {
      free_something(node_to_delete->thing);
      free(node_to_delete);
    }
    
    ...
    
    void thread (void* x)
    {
      lock(x->lock);
        //...do something that could probably change x->data_ptr->data... to 0
        if(x->data_ptr->data == 0)
        {
          free_something(x->data_ptr->data);
        }
      unlock(x->lock);
    }
    
    
    
     AcquireSRWLockExclusive(lock);
      if(_x->o->data==0)
        free(_x);
     ReleaseSRWLockExclusive(lock);
    

    作为旁注,Windows 的 C 程序永远不会返回 void。托管的 C 程序必须始终返回 int。您的程序无法在 C 编译器上编译。

    此外,CreateThread() 需要一个指向函数的函数指针,该函数返回一个 32 位值并将一个 void 指针作为参数。您传递了不同类型的函数指针,C 中不允许函数指针强制转换,我也不确定如果 Windows 获得与预期不同的函数指针,它会执行什么样的疯狂。您调用未定义的行为。这可能会导致您的程序崩溃或以意外或随机的方式运行。

    你需要把你的线程函数改成DWORD WINAPI thread (LPVOID param);

    【讨论】:

    • 你是对的,现在唯一的方法似乎是让线程阻塞列表而不是单个节点的操作。我不愿意这样说的原因是我希望多个线程访问列表中的节点,并且无论如何之前已经在线程的上下文中引用过,而不是每次都在列表上执行迭代。从这个意义上说,线程可能不持有对列表的引用,而只是对节点的引用。通过这样做,我期待更少的争论。但现在我意识到这样的争论是不可避免的。非常感谢。
    • @Y.Z 没有什么能阻止多个线程访问单个节点,这就是锁存在的原因。我的示例中的“something_t”应该是链表节点。我想说的是,您只需将实际数据的分配/释放与链表节点的分配/释放分开,并将锁保留在节点中,而不是与数据。
    猜你喜欢
    • 1970-01-01
    • 2018-12-18
    • 1970-01-01
    • 2011-01-25
    • 2011-12-04
    • 2015-08-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    相关资源
    最近更新 更多