OpenMP 《并行程序设计导论》的补充代码
▶ 使用 OpenMP 和队列数据结构,在各线程之间传递信息
● 代码,使用 critical 子句和 atomic 指令来进行读写保护
// queue.h
#ifndef _QUEUE_H_
#define _QUEUE_H_ struct queue_node_s // 定义队列结点,包含信息来源,信息内容,下一个结点的指针
{
int src;
int mesg;
struct queue_node_s* next_p;
}; struct queue_s // 定义队列,包含入队数,出队数,头尾指针
{
int enqueued;
int dequeued;
struct queue_node_s* front_p;
struct queue_node_s* tail_p;
}; struct queue_s* Allocate_queue(void);
void Free_queue(struct queue_s* q_p);
void Print_queue(struct queue_s* q_p);
void Enqueue(struct queue_s* q_p, int src, int mesg);
int Dequeue(struct queue_s* q_p, int* src_p, int* mesg_p);
int Search(struct queue_s* q_p, int mesg, int* src_p);
#endif // queue.c
#include <stdio.h>
#include <stdlib.h>
#include "queue.h" #ifdef USE_MAIN
int main(void)//检验函数
{
char op;
int src, mesg;
struct queue_s *q_p = Allocate_queue();
for (printf("Op? (e, d, p, s, f, q)\n"), scanf(" %c", &op); op != 'q' && op != 'Q'; printf("Op? (e, d, p, s, f, q)\n"), scanf(" %c", &op));
{
switch (op)
{
case 'e':
case 'E':
printf("Src? Mesg?\n");
scanf("%d%d", &src, &mesg);
Enqueue(q_p, src, mesg);
break;
case 'd':
case 'D':
if (Dequeue(q_p, &src, &mesg))
printf("Dequeued src = %d, mesg = %d\n", src, mesg);
else
printf("Queue is empty\n");
break;
case 's':
case 'S':
printf("Mesg?\n");
scanf("%d", &mesg);
if (Search(q_p, mesg, &src))
printf("Found %d from %d\n", mesg, src);
else
printf("Didn't find %d\n", mesg);
break;
case 'p':
case 'P':
Print_queue(q_p);
break;
case 'f':
case 'F':
Free_queue(q_p);
break;
default:
printf("%c isn't a valid command\n", op);
printf("Please try again\n");
}
}
Free_queue(q_p);
free(q_p);
return ;
}
#endif struct queue_s* Allocate_queue()// 创建队列
{
struct queue_s *q_p = malloc(sizeof(struct queue_s));
q_p->enqueued = q_p->dequeued = ;
q_p->front_p = q_p->tail_p = NULL;
return q_p;
} void Free_queue(struct queue_s* q_p)// 释放队列
{
struct queue_node_s *curr_p, *temp_p;
for (curr_p = q_p->front_p; curr_p != NULL; temp_p = curr_p, curr_p = curr_p->next_p, free(temp_p));
q_p->enqueued = q_p->dequeued = ;
q_p->front_p = q_p->tail_p = NULL;
} void Print_queue(struct queue_s* q_p)// 打印队列
{
struct queue_node_s *curr_p;
printf("queue = \n");
for (curr_p = q_p->front_p; curr_p != NULL; curr_p = curr_p->next_p)
printf(" src = %d, mesg = %d\n", curr_p->src, curr_p->mesg);
printf("enqueued = %d, dequeued = %d\n", q_p->enqueued, q_p->dequeued);
printf("\n");
} void Enqueue(struct queue_s* q_p, int src, int mesg)// 入队,按信息 src 和 mesg 向队列 q_p 添加结点
{
struct queue_node_s *n_p = malloc(sizeof(struct queue_node_s));
n_p->src = src;
n_p->mesg = mesg;
n_p->next_p = NULL;
if (q_p->tail_p == NULL)
{
q_p->front_p = n_p;
q_p->tail_p = n_p;
}
else
{
q_p->tail_p->next_p = n_p;
q_p->tail_p = n_p;
}
q_p->enqueued++;
} int Dequeue(struct queue_s* q_p, int* src_p, int* mesg_p)// 出队,信息放入 src_p 和 mesg_p
{
struct queue_node_s* temp_p;
if (q_p->front_p == NULL)
return ;
*src_p = q_p->front_p->src;
*mesg_p = q_p->front_p->mesg;
temp_p = q_p->front_p;
if (q_p->front_p == q_p->tail_p)
q_p->front_p = q_p->tail_p = NULL;
else
q_p->front_p = temp_p->next_p;
free(temp_p);
q_p->dequeued++;
return ;
} int Search(struct queue_s* q_p, int mesg, int* src_p)// 查找操作
{
struct queue_node_s *curr_p;
for (curr_p = q_p->front_p; curr_p != NULL; curr_p = curr_p->next_p)
{
if (curr_p->mesg == mesg)
{
*src_p = curr_p->src;
return ;
}
}
return ;
} // omp_msgps.c
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include "queue.h" const int MAX_MSG = ; void Usage(char *prog_name)// 输入参数错误时提示信息
{
fprintf(stderr, "usage: %s <number of threads> <number of messages>\n", prog_name);
fprintf(stderr, " number of messages = number sent by each thread\n");
getchar();
exit();
} void Send_msg(struct queue_s* msg_queues[], int my_rank, int thread_count, int msg_number)// 发送信息给 dest 的队列
{
int mesg = rand() % MAX_MSG;// int mesg = -msg_number;
int dest = rand() % thread_count;
# pragma omp critical
Enqueue(msg_queues[dest], my_rank, mesg);
# ifdef DEBUG
printf("Thread %d > sent %d to %d\n", my_rank, mesg, dest);
# endif
} void Try_receive(struct queue_s* q_p, int my_rank)// 如果队列 q_p 不空,则接受信息
{
int src, mesg;
int queue_size = q_p->enqueued - q_p->dequeued;
if (queue_size == )
return;
else if (queue_size == )
# pragma omp critical
Dequeue(q_p, &src, &mesg);
else
Dequeue(q_p, &src, &mesg);
printf("Thread %d > received %d from %d\n", my_rank, mesg, src);
} int Done(struct queue_s* q_p, int done_sending, int thread_count)// 检查是否空队
{
int queue_size = q_p->enqueued - q_p->dequeued;
if (queue_size == && done_sending == thread_count)
return ;
return ;
} int main(int argc, char* argv[])
{
int thread_count, send_max, done_sending;
struct queue_s** msg_queues;
if (argc != || (thread_count = strtol(argv[], NULL, )) <= || (send_max = strtol(argv[], NULL, ) < ))
Usage(argv[]);
msg_queues = malloc(thread_count * sizeof(struct queue_node_s*));
done_sending = ; # pragma omp parallel num_threads(thread_count) default(none) shared(thread_count, send_max, msg_queues, done_sending)
{
int my_rank = omp_get_thread_num(), msg_number;
srand(my_rank);
msg_queues[my_rank] = Allocate_queue(); # pragma omp barrier// 等待所有线程都建好队列在开始收发信息 for (msg_number = ; msg_number < send_max; msg_number++)// 每个线程都发送 send_max 个信息
{
Send_msg(msg_queues, my_rank, thread_count, msg_number);
Try_receive(msg_queues[my_rank], my_rank);
}
# pragma omp atomic
done_sending++;
# ifdef DEBUG
printf("Thread %d > done sending\n", my_rank);
# endif while (!Done(msg_queues[my_rank], done_sending, thread_count))
Try_receive(msg_queues[my_rank], my_rank); Free_queue(msg_queues[my_rank]);
free(msg_queues[my_rank]);
}
free(msg_queues);
getchar();
return ;
}
● 代码,使用 omp 锁来进行读写保护
// queue_lk.h
#ifndef _QUEUE_LK_H_
#define _QUEUE_LK_H_
#include <omp.h> struct queue_node_s
{
int src;
int mesg;
struct queue_node_s* next_p;
}; struct queue_s// 定义队列,多一个 omp_lock_t
{
omp_lock_t lock;
int enqueued;
int dequeued;
struct queue_node_s* front_p;
struct queue_node_s* tail_p;
}; struct queue_s* Allocate_queue(void);
void Free_queue(struct queue_s* q_p);
void Print_queue(struct queue_s* q_p);
void Enqueue(struct queue_s* q_p, int src, int mesg);
int Dequeue(struct queue_s* q_p, int* src_p, int* mesg_p);
int Search(struct queue_s* q_p, int mesg, int* src_p);
#endif // queue_lk.c
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include "queue_lk.h" #ifdef USE_MAIN
int main(void)
{
char op;
int src, mesg, not_empty;
struct queue_s *q_p = Allocate_queue();
for (printf("Op? (e, d, p, s, f, q)\n"), scanf(" %c", &op); op != 'q' && op != 'Q'; printf("Op? (e, d, p, s, f, q)\n"), scanf(" %c", &op))
{
switch (op)
{
case 'e':
case 'E':
printf("Src? Mesg?\n");
scanf("%d%d", &src, &mesg);
omp_set_lock(&q_p->lock);// DIFF
Enqueue(q_p, src, mesg);
omp_unset_lock(&q_p->lock);
break;
case 'd':
case 'D':
omp_set_lock(&q_p->lock);// DIFF,注意把出队放在锁中间,而判断空队则是在释放锁以后进行
not_empty = Dequeue(q_p, &src, &mesg);
omp_unset_lock(&q_p->lock);
if (not_empty)
printf("Dequeued src = %d, mesg = %d\n", src, mesg);
else
printf("Queue is empty\n");
break;
case 's':
case 'S':
printf("Mesg?\n");
scanf("%d", &mesg);
if (Search(q_p, mesg, &src))
printf("Found %d from %d\n", mesg, src);
else
printf("Didn't find %d\n", mesg);
break;
case 'p':
case 'P':
Print_queue(q_p);
break;
case 'f':
case 'F':
omp_set_lock(&q_p->lock);// DIFF
Free_queue(q_p);
omp_unset_lock(&q_p->lock);
break;
default:
printf("%c isn't a valid command\n", op);
printf("Please try again\n");
}
}
Free_queue(q_p);
omp_destroy_lock(&q_p->lock);// DIFF
free(q_p);
return ;
}
#endif struct queue_s* Allocate_queue()
{
struct queue_s *q_p = malloc(sizeof(struct queue_s));
q_p->enqueued = q_p->dequeued = ;
q_p->front_p = q_p->tail_p = NULL;
omp_init_lock(&q_p->lock);// DIFF
return q_p;
} void Free_queue(struct queue_s* q_p)
{
struct queue_node_s *curr_p, *temp_p;
for (curr_p = q_p->front_p; curr_p != NULL; temp_p = curr_p, curr_p = curr_p->next_p, free(temp_p));
q_p->enqueued = q_p->dequeued = ;
q_p->front_p = q_p->tail_p = NULL;
} void Print_queue(struct queue_s* q_p)
{
struct queue_node_s *curr_p;
printf("queue = \n");
for (curr_p = q_p->front_p; curr_p != NULL; curr_p = curr_p->next_p)
printf(" src = %d, mesg = %d\n", curr_p->src, curr_p->mesg);
printf("enqueued = %d, dequeued = %d\n", q_p->enqueued, q_p->dequeued);
printf("\n");
} void Enqueue(struct queue_s* q_p, int src, int mesg)
{
struct queue_node_s *n_p = malloc(sizeof(struct queue_node_s));
n_p->src = src;
n_p->mesg = mesg;
n_p->next_p = NULL;
if (q_p->tail_p == NULL)
{
q_p->front_p = n_p;
q_p->tail_p = n_p;
}
else
{
q_p->tail_p->next_p = n_p;
q_p->tail_p = n_p;
}
q_p->enqueued++;
} int Dequeue(struct queue_s* q_p, int* src_p, int* mesg_p)
{
struct queue_node_s* temp_p;
if (q_p->front_p == NULL)
return ;
*src_p = q_p->front_p->src;
*mesg_p = q_p->front_p->mesg;
temp_p = q_p->front_p;
if (q_p->front_p == q_p->tail_p)
q_p->front_p = q_p->tail_p = NULL;
else
q_p->front_p = temp_p->next_p;
free(temp_p);
q_p->dequeued++;
return ;
} int Search(struct queue_s* q_p, int mesg, int* src_p)
{
struct queue_node_s *curr_p;
for (curr_p = q_p->front_p; curr_p != NULL; curr_p = curr_p->next_p)
{
if (curr_p->mesg == mesg)
{
*src_p = curr_p->src;
return ;
}
}
return ;
} // omp_msglk.c
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include "queue_lk.h" const int MAX_MSG = ; void Usage(char *prog_name)
{
fprintf(stderr, "usage: %s <number of threads> <number of messages>\n", prog_name);
fprintf(stderr, " number of messages = number sent by each thread\n");
getchar();
exit();
} void Send_msg(struct queue_s* msg_queues[], int my_rank, int thread_count, int msg_number)
{
int mesg = random() % MAX_MSG;// int mesg = -msg_number;
int dest = random() % thread_count;
struct queue_s* q_p = msg_queues[dest];
omp_set_lock(&q_p->lock);// DIFF
Enqueue(q_p, my_rank, mesg);
omp_unset_lock(&q_p->lock);
# ifdef DEBUG
printf("Thread %d > sent %d to %d\n", my_rank, mesg, dest);
# endif
} void Try_receive(struct queue_s* q_p, int my_rank)
{
int src, mesg;
int queue_size = q_p->enqueued - q_p->dequeued;
if (queue_size == )
return;
else if (queue_size == )
{
omp_set_lock(&q_p->lock);// DIFF
Dequeue(q_p, &src, &mesg);
omp_unset_lock(&q_p->lock);
}
else
Dequeue(q_p, &src, &mesg);
printf("Thread %d > received %d from %d\n", my_rank, mesg, src);
} int Done(struct queue_s* q_p, int done_sending, int thread_count)
{
int queue_size = q_p->enqueued - q_p->dequeued;
if (queue_size == && done_sending == thread_count)
return ;
return ;
} int main(int argc, char* argv[])
{
int thread_count, send_max, done_sending;
struct queue_s** msg_queues;
if (argc != || (thread_count = strtol(argv[], NULL, )) <= || (send_max = strtol(argv[], NULL, ) < ))
Usage(argv[]);
msg_queues = malloc(thread_count * sizeof(struct queue_node_s*));
done_sending = ; # pragma omp parallel num_threads(thread_count) default(none) shared(thread_count, send_max, msg_queues, done_sending)
{
int my_rank = omp_get_thread_num(), msg_number;
srand(my_rank);
msg_queues[my_rank] = Allocate_queue(); # pragma omp barrier for (msg_number = ; msg_number < send_max; msg_number++)
{
Send_msg(msg_queues, my_rank, thread_count, msg_number);
Try_receive(msg_queues[my_rank], my_rank);
}
# pragma omp atomic
done_sending++;
# ifdef DEBUG
printf("Thread %d > done sending\n", my_rank);
# endif while (!Done(msg_queues[my_rank], done_sending, thread_count))
Try_receive(msg_queues[my_rank], my_rank); Free_queue(msg_queues[my_rank]);
free(msg_queues[my_rank]);
}
free(msg_queues);
getchar();
return ;
}
OpenMP 《并行程序设计导论》的补充代码的更多相关文章
- 《并行程序设计导论》——MPI(Microsoft MPI)(1):Hello
=================================版权声明================================= 版权声明:原创文章 禁止转载 请通过右侧公告中的“联系邮 ...
- OpenMP并行程序设计——for循环并行化详解
在C/C++中使用OpenMP优化代码方便又简单,代码中需要并行处理的往往是一些比较耗时的for循环,所以重点介绍一下OpenMP中for循环的应用.个人感觉只要掌握了文中讲的这些就足够了,如果想要学 ...
- OpenMP并行程序设计
1.fork/join并行执行模式的概念 2.OpenMP指令和库函数介绍 3.parallel 指令的用法 4.for指令的使用方法 5 sections和section指令的用法 1.fork/j ...
- OpenMP 并行程序设计入门
OpenMP 是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 0. 一段使用 OpenMP 的并行程序 #include <stdio.h> #inclu ...
- Pthreads 《并行程序设计导论》的补充代码
▶ 关于单链表的访问,插入结点和删除结点操作,并且将其推广到多线程中去. ● 代码,通用的随机数生成 // my_rand.h #ifndef _MY_RAND_H_ #define _MY_RAND ...
- 《并行程序设计导论》——OpenMP
OpenMP看着很好,实际上坑很多. 如果真的要求性能和利用率,还是专门写代码吧.而且MS的VS里只有2.X的版本.
- 《并行程序设计导论》——Pthreads
这部分不需要看了. 因为C++11和BOOST比这个Pthreads要好一点. 如果不考虑移植性,在Windows平台上用核心编程的东西比C++11和BOOST更好控制.
- 《并行程序设计导论》——MPI(Microsoft MPI)(6):并行排序算法
=================================版权声明================================= 版权声明:原创文章 禁止转载 请通过右侧公告中的“联系邮 ...
- openMP编程(上篇)之并行程序设计
openMP简介 openMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 当计算机升级到多核时,程序中创建的线程数量需要随CPU核数变化,如在CPU核数超过线程数 ...
随机推荐
- module.exports和exports
require 用来加载代码,而 exports 和 module.exports 则用来导出代码.但很多新手可能会迷惑于 exports 和 module.exports 的区别,为了更好的理解 e ...
- 040——VUE中组件之组件间的数据参props的使用实例操作
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue 子组件把数据传递给父组件
<div id="app"> <child v-on:drop='parent'></child> //这里v-on:drop="pa ...
- HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4
http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极 ...
- Python3 运算符(八)
什么是运算符? 举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为操作数,"+" 称为运算符. Python语言支持以下类型的运算符: 算术运算符 比较(关系)运算符 ...
- -webkit新属性 image-set和srcset
响应式图片的作用: 为使用不同分辨率的不同浏览器用户提供适合其浏览环境的图片大小的解决方案. 之前的解决方法是使用@media 但是-webkit新提出的image-set和srcset同样可以解决问 ...
- L185 Ocean Shock
This is part of "Ocean Shock," a Reuters series exploring climate change's impact on sea c ...
- PostgreSQL psql中如何查看快捷功能的对应函数
在psql中,我们可以通过一系列的的快捷命令查看数据库元素,如:\d 查看当前搜索路径下的表,那么内部用到的SQL语句是什么呢,可以通过命令来设置是否打印出来: apple=# \set ECHO_H ...
- python 之 多线程、多进程代码
thread-多线程 multiprocessing-多进程 #!/usr/bin/python # -*- coding:utf-8 -*- import os import threading i ...
- 回测框架pybacktest简介(一)
pybacktest 教程 本教程让你快速了解 pybacktest's 的功能.为此,我们回测精典交易策略移动平均线MA交叉. MA快线上穿慢线时,买进做多 MA快线下穿慢线时,卖出做空 进场规则, ...