OpenMP(三)#pragma omp critical

问题描述:

这是一段给链表添加节点的函数:

void addToList(int data)
{
 item_t * newItem = (item_t *) malloc(sizeof(item_t));
 newItem->data = data;
 newItem->next = NULL;

 // Find tail and add newItem to it.
 if(head == NULL) // i.e. list is empty .
 {
    head = newItem;
 }
 else // Find end of list and add to it.
 {
    item_t *tail = head;
    while (tail->next != NULL){
        tail = tail->next;
    }
    tail->next = newItem;
 }
}

并行化调用addToList函数:

#pragma omp parallel for
for(i = 0; i < numAdd; i++){
    addToList ( i );
}

但在运行后发现,一些元素并没有如期加入链表,而是直接丢失了。此外,那些丢失的元素也会占用空间,且这些空间没有被释放。这不满足tread safe的条件。

注意: thread safe不意味着高效率,很多时候都会牺牲效率来成全thread safe。

造成以上问题的原因:

1. *head 头指针是被多个线程共享的,可能会导致data race。例如:

线程A认为head == NULL,希望把值1赋给head,

同时线程B也认为head == NULL,并率先把值2赋给head

线程A再把值赋给head,覆盖掉了线程B的操作,最终导致2这个值丢失。

2. *tail指针是被多个线程共享的,可能会导致data race。情况类似头指针。

那能否用OpenMP(二)并行运算中的数据依赖问题中解决data race的方法来解决这个问题呢?

如果把*head指针或*tail变成private的,是不可行的,因为这两个指针是整个链表共享的,不是每个线程私有的。

解决方法:使用#pragma omp critical{ }

这行代码的作用是,在{ }范围内的代码属于critical region。

#pragma omp critical
{
  ... //critical region
}

如果有某个线程率先达到了critical region, 其他线程就不能进入这个区域,直到占领这个区域的线程离开。

改法1:在调用addToList函数处使用#pragma omp critical{ }。

#pragma omp parallel for
for(i = 0; i < numAdd; i++){
    #pragma omp critical
    { 
        addToList(i);
    }   
}

但这种方法是低效的,因为在代码执行过程中,只有一个线程可以抵达critical region,这本质上和按顺序执行没有区别。

改法2:在addToList函数中使用#pragma omp critical{ }。

在addToList函数中添加critical region。由于函数的前三步不存在多线程data race问题,每个线程都需要独立创造空间存放数据和指针,所以不需要将其纳入cirtical region。

void addToList(int data)
{
 item_t * newItem = (item_t *) malloc(sizeof(item_t));
 newItem->data = data;
 newItem->next = NULL;
 #pragma omp parallel for
 {
    // Find tail and add newItem to it.
    if(head == NULL) // i.e. list is empty .
    {
        head = newItem;
    }
    else // Find end of list and add to it.
    {
        item_t *tail = head;
        while (tail->next != NULL){
            tail = tail->next;
        }
        tail->next = newItem;
    }
 }
}

由于函数的前三步是并行执行的,改法2比改法1效率有所提升,但也称不上高效。

使用#pragma omp critical{ }的其他注意点:

1. 无法直接嵌套critical region,因为这两个critical region会使用同一个锁。

#pragma omp critical
{ 
    ...

    #pragma omp critical
    { 
       ...
    }
}

2. 可以通过给critical region命名来嵌套使用。这时,每个critical region都会拥有自己独有的锁。

#pragma omp critical (OUTER)
{ 
    ...

    #pragma omp critical (INNER)
    { 
       ...
    }
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值