openmp 互斥锁 mysql_OpenMP(四)线程同步之互斥锁函数
線程同步之互斥鎖函數
前文介紹了互斥鎖同步的兩種方法:atomic和critical,本章介紹OpenMP提供的互斥鎖函數?;コ怄i函數類似于Windows、Linux下的mutex。
1. 互斥鎖函數
函數聲明?????????????????????????????????????????????????????????????????? 功能
void omp_init_lock(omp_lock*)?????????????????????????????? 初始化互斥器
void omp_destroy_lock(omp_lock*)??????????????????????? 銷毀互斥器
void omp_set_lock(omp_lock*)?????????????????????????????? 獲得互斥器
void omp_unset_lock(omp_lock*)?????????????????????????? 釋放互斥器
void omp_test_lock(omp_lock*)????????????????????????????? 試圖獲得互斥器,如果獲得成功則返回true,否則返回false
2. 互斥鎖示例
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#include?
#include?
static?omp_lock_t?lock;
int?main()
{
omp_init_lock(&lock);?//初始化互斥鎖
#pragma?omp?parallel?for
for(int?i?=?0;?i?
{
omp_set_lock(&lock);???//獲得互斥器
std::cout?<
std::cout?<
omp_unset_lock(&lock);?//釋放互斥器
}
omp_destroy_lock(&lock);??//銷毀互斥器
return?0;
}
#include
#include
static omp_lock_t lock;
int main()
{
omp_init_lock(&lock); //初始化互斥鎖
#pragma omp parallel for
for(int i = 0; i < 5; ++i)
{
omp_set_lock(&lock); //獲得互斥器
std::cout << omp_get_thread_num() << "+" << std::endl;
std::cout << omp_get_thread_num() << "-" << std::endl;
omp_unset_lock(&lock); //釋放互斥器
}
omp_destroy_lock(&lock); //銷毀互斥器
return 0;
}
上邊的示例對for循環中的所有內容進行加鎖保護,同時只能有一個線程執行for循環中的內容。
線程1或線程2在執行for循環內部代碼時不會被打斷。如果刪除代碼中的獲得鎖釋放鎖的代碼,則相當于沒有互斥鎖。
互斥鎖函數中只有omp_test_lock函數是帶有返回值的,該函數可以看作是omp_set_lock的非阻塞版本。
線程同步之事件同步機制
1. 引言
前邊已經提到,線程的同步機制包括互斥鎖同步和事件同步。互斥鎖同步包括atomic、critical、mutex函數,其機制與普通多線程同步的機制類似。而事件同步則通過nowait、sections、single、master等預處理指示符聲明來完成。
2. 隱式柵障
在開始之前,先介紹一下并行區域中的隱式柵障。
柵障(Barrier)是OpenMP用于線程同步的一種方法。線程遇到柵障時必須等待,直到并行的所有線程都到達同一點。
注意:
在任務分配for循環和任務分配section結構中隱含了柵障,在parallel, for, sections, single結構的最后,也會有一個隱式的柵障。
隱式的柵障。
隱式的柵障會使線程等到所有的線程繼續完成當前的循環、結構化塊或并行區,再繼續執行后續工作??梢允褂胣owait去掉這個隱式的柵障。
3. nowait事件同步
nowait用來取消柵障,其用法如下:
#pragma omp for nowait? //不能使用#pragma omp parallel for nowait
或
#pragma omp single nowait
示例:
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#include?
#include?
int?main()
{
#pragma?omp?parallel
{
#pragma?omp?for?nowait
for(int?i?=?0;?i?
{
std::cout?<
}
#pragma?omp?for
for(int?j?=?0;?j?
{
std::cout?<
}
}
return?0;
}
#include
#include
int main()
{
#pragma omp parallel
{
#pragma omp for nowait
for(int i = 0; i < 1000; ++i)
{
std::cout << i << "+" << std::endl;
}
#pragma omp for
for(int j = 0; j < 10; ++j)
{
std::cout << j << "-" << std::endl;
}
}
return 0;
}
運行程序,可以看到第一個for循環的兩個線程中的一個執行完之后,繼續向下執行,因此同時打印了第一個循環的+和第二個循環的-。
如果去掉第一個for循環的nowait生命,則第一個for循環的兩個線程都執行完之后,才開始同時執行第二個for循環。也就是說,通過#pragma omp for聲明的for循環結束時有一個默認的隱式柵障。
4. 顯示同步柵障 #pragma omp barrier
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#include?
#include?
int?main()
{
#pragma?omp?parallel
{
for(int?i?=?0;?i?
{
std::cout?<
}
#pragma?om?barrier
for(int?j?=?0;?j?
{
std::cout?<
}
}
return?0;
}
#include
#include
int main()
{
#pragma omp parallel
{
for(int i = 0; i < 100; ++i)
{
std::cout << i << "+" << std::endl;
}
#pragma om barrier
for(int j = 0; j < 10; ++j)
{
std::cout << j << "-" << std::endl;
}
}
return 0;
}
運行程序,可以看出兩個線程執行了第一個for循環,當兩個線程同時執行完第一個for循環之后,在barrier處進行了同步,然后執行后邊的for循環。
5. master事件同步
通過#pragma om master來聲明對應的并行程序塊只有主線程完成。
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#include?
#include?
int?main()
{
#pragma?omp?parallel
{
#pragma?omp?master
{
for(int?j?=?0;?j?
{
std::cout?<
}
}
std::cout?<
}
return?0;
}
#include
#include
int main()
{
#pragma omp parallel
{
#pragma omp master
{
for(int j = 0; j < 10; ++j)
{
std::cout << j << "-" << std::endl;
}
}
std::cout << "This will printed twice." << std::endl;
}
return 0;
}
運行程序,可以看到,進入parallel聲明的并行區域之后,創建了兩個線程。主線程執行了for循環,而另一個線程沒有執行for循環,而直接進入了for循環之后的打印語句,然后執行for循環的線程隨后還會再執行一次后邊的打印語句。
6. sections用來指定不同的線程執行不同的部分
下面通過一個實例來說明其使用方法:
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
#include?
#include?
int?main()
{
//聲明該并行區域分為若干個section,section之間的運行順序為并行
//的關系
#pragma?omp?parallel?sections
for(int?i?=?0;?i?
{
std::cout?<
}
#pragma?omp?section???//第一個section,由某個線程單獨完成
for(int?j?=?0;?j?
{
std::cout?<
}
return?0;
}
#include
#include
int main()
{
//聲明該并行區域分為若干個section,section之間的運行順序為并行
//的關系
#pragma omp parallel sections
for(int i = 0; i < 5; ++i)
{
std::cout << i << "+" << std::endl;
}
#pragma omp section //第一個section,由某個線程單獨完成
for(int j = 0; j < 5; ++j)
{
std::cout << j << "-" << std::endl;
}
return 0;
}
可以看到,并行區域中有兩個線程,所以兩個section同時執行。
總結
以上是生活随笔為你收集整理的openmp 互斥锁 mysql_OpenMP(四)线程同步之互斥锁函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python灰色预测模型步骤人口预测_人
- 下一篇: Nginx源码目录介绍