Pthreads 《并行程序设计导论》的补充代码

▶ 关于单链表的访问,插入结点和删除结点操作,并且将其推广到多线程中去。

● 代码,通用的随机数生成

 // my_rand.h
#ifndef _MY_RAND_H_
#define _MY_RAND_H_ unsigned my_rand(unsigned* a_p);
double my_drand(unsigned* a_p); #endif // my_rand.c
#include <stdio.h>
#include <stdlib.h>
#include "my_rand.h" #define MR_MULTIPLIER 279470273
#define MR_INCREMENT 0
#define MR_MODULUS 4294967291U
#define MR_DIVISOR ((double) 4294967291U) #ifdef _MAIN_
int main(void)
{
int n, i;
unsigned seed = , x;
double y;
printf("How many random numbers?\n");
scanf("%d", &n); x = my_rand(&seed);
for (i = ; i < n; i++)
{
x = my_rand(&x);
printf("%u\n", x);
}
for (i = ; i < n; i++)
{
y = my_drand(&x);
printf("%e\n", y);
}
return ;
}
#endif unsigned my_rand(unsigned* seed_p)// 产生 0 ~ MR_MODULUS - 1 之间的随机整数
{
long long z = *seed_p;
z = (z * MR_MULTIPLIER + MR_INCREMENT) % MR_MODULUS;
*seed_p = z;
return z;
} double my_drand(unsigned* seed_p)// 产生 0 ~ 1 之间的随机双精度浮点数
{
return (double)my_rand(seed_p) / MR_DIVISOR;
}

● 代码,单线程

 // linked_list.c
#include <stdio.h>
#include <stdlib.h> struct list_node_s
{
int data;
struct list_node_s* next;
}; int Insert(int value, struct list_node_s** head_pp) // 插入结点
{
struct list_node_s *curr_p, *pred_p, *temp_p;
for (curr_p = *head_pp, pred_p = NULL; curr_p != NULL && curr_p->data < value; pred_p = curr_p, curr_p = curr_p->next);// 搜索目标位置
if (curr_p == NULL || curr_p->data > value) // 找到了目标位置
{
temp_p = malloc(sizeof(struct list_node_s));
temp_p->data = value;
temp_p->next = curr_p;
if (pred_p == NULL)
*head_pp = temp_p;
else
pred_p->next = temp_p;
return ;
}
printf("%d is already in the list\n", value);// 其他情况,目标结点已经存在(链表元素不允许重复)
return ;
} void Print(struct list_node_s* head_p) // 打印单链表
{
struct list_node_s *curr_p;
printf("list = ");
for (curr_p = head_p; curr_p != (struct list_node_s*) NULL; curr_p = curr_p->next)
printf("%d ", curr_p->data);
printf("\n");
return;
} int Member(int value, struct list_node_s* head_p) // 查找元素 value
{
struct list_node_s *curr_p; for (curr_p = head_p; curr_p != NULL && curr_p->data < value; curr_p = curr_p->next);
if (curr_p == NULL || curr_p->data > value)
{
printf("%d is not in the list\n", value);
return ;
}
printf("%d is in the list\n", value);
return ;
} int Delete(int value, struct list_node_s** head_pp) // 删除指定结点
{
struct list_node_s *curr_p = *head_pp, *pred_p = NULL;
for (curr_p = *head_pp, pred_p = NULL; curr_p != NULL && curr_p->data < value; pred_p = curr_p, curr_p = curr_p->next);
if (curr_p != NULL && curr_p->data == value)
{
if (pred_p == NULL)
{
*head_pp = curr_p->next;
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
free(curr_p);
}
else
{
pred_p->next = curr_p->next;
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
free(curr_p);
}
return ;
}
printf("%d is not in the list\n", value);
return ;
} int Is_empty(struct list_node_s* head_p) // 判断是否为空表
{
return head_p == NULL;
} void Free_list(struct list_node_s** head_pp) // 释放单链表
{
struct list_node_s *curr_p, *succ_p;
if (Is_empty(*head_pp))
return;
for (curr_p = *head_pp, succ_p = curr_p->next; succ_p != NULL; free(curr_p), curr_p = succ_p, succ_p = curr_p->next)
{
# ifdef DEBUG
printf("Freeing %d\n", curr_p->data);
# endif
}
# ifdef DEBUG
printf("Freeing %d\n", curr_p->data);
# endif
free(curr_p);
*head_pp = NULL;
} char Get_command(void) // 读取下一个命令字符
{
char c;
printf("Please enter a command: ");
scanf(" %c", &c);
return c;
} int Get_value(void) // 读取下一个命令值
{
int val;
printf("Please enter a value: ");
scanf("%d", &val);
return val;
} int main(void)
{
char command;
int value;
struct list_node_s *head_p = NULL;
for (command = Get_command(); command != 'q' && command != 'Q';)
{
switch (command)// 逐命令运行,忽略个操作函数的返回值
{
case 'i':
case 'I':
value = Get_value();
Insert(value, &head_p);
break;
case 'p':
case 'P':
Print(head_p);
break;
case 'm':
case 'M':
value = Get_value();
Member(value, head_p);
break;
case 'd':
case 'D':
value = Get_value();
Delete(value, &head_p);
break;
default:
printf("There is no %c command\n", command);
printf("Please try again\n");
}
command = Get_command();
}
Free_list(&head_p);
return ;
}

● 代码,使用单互斥量

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "my_rand.h" const int MAX_KEY = ; struct list_node_s
{
int data;
struct list_node_s* next;
}; struct list_node_s *head = NULL;// 链表头结点
int thread_count; // 线程数
int total_ops; // 总操作数
double insert_percent; // 插入操作比例
double search_percent; // 查找操作比例
double delete_percent; // 删除操作比例
pthread_mutex_t mutex; // 线程操作互斥量
pthread_mutex_t count_mutex; // 线程操作数写入全局和时候的互斥量
int member_total = , insert_total = , delete_total = ;// 全局操作数统计 void Usage(char* prog_name)
{
fprintf(stderr, "usage: %s <thread_count>\n", prog_name);
exit();
} void Get_input(int* inserts_in_main_p)// 主函数中用于输入的函数
{
printf("How many keys should be inserted in the main thread?\n");
scanf("%d", inserts_in_main_p);
printf("How many total ops should be executed?\n");
scanf("%d", &total_ops);
printf("Percent of ops that should be searches? (between 0 and 1)\n");
scanf("%lf", &search_percent);
printf("Percent of ops that should be inserts? (between 0 and 1)\n");
scanf("%lf", &insert_percent);
delete_percent = 1.0 - (search_percent + insert_percent);
} int Insert(int value)// 插入结点
{
struct list_node_s *curr, *pred, *temp;
for (curr = head, pred = NULL; curr != NULL && curr->data < value; pred = curr, curr = curr->next);
if (curr == NULL || curr->data > value)
{
temp = malloc(sizeof(struct list_node_s));
temp->data = value;
temp->next = curr;
if (pred == NULL)
head = temp;
else
pred->next = temp;
return ;
}
printf("%d is already in the list\n", value);
return ;
} void Print(void)
{
struct list_node_s *temp;
printf("list = ");
for (temp = head; temp != (struct list_node_s*) NULL; temp = temp->next)
printf("%d ", temp->data);
printf("\n");
} int Member(int value)
{
struct list_node_s *temp;
for (temp = head; temp != NULL && temp->data < value; temp = temp->next);
if (temp == NULL || temp->data > value)
{
# ifdef DEBUG
printf("%d is not in the list\n", value);
# endif
return ;
}
# ifdef DEBUG
printf("%d is in the list\n", value);
# endif
return ;
} int Delete(int value)
{
struct list_node_s *curr, *pred;
for (curr = head, pred = NULL; curr != NULL && curr->data < value; pred = curr, curr = curr->next);
if (curr != NULL && curr->data == value)
{
if (pred == NULL)
head = curr->next;
else
pred->next = curr->next;
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
free(curr);
return ;
}
return ;
} int Is_empty(void)
{
return head == NULL;
} void Free_list(void)
{
struct list_node_s *current, *following;
if (Is_empty())
return;
for (current = head, following = current->next; following != NULL; free(current), current = following, following = current->next)
{
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
}
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
free(current);
} void* Thread_work(void* rank)// 调度各种链表工作的函数
{
int i, my_member, my_insert, my_delete;
unsigned seed = (long)rank + ;
double which_op;
for (i = my_member = my_insert = my_delete = ; i < total_ops / thread_count; i++)
{
which_op = my_drand(&seed);
if (which_op < search_percent)// 随机数小于设定的搜索概率,执行搜索操作
{
pthread_mutex_lock(&mutex);
Member(my_rand(&seed) % MAX_KEY);
pthread_mutex_unlock(&mutex);
my_member++;
}
else if (which_op < search_percent + insert_percent)// 随机数小于搜索和插入概率,执行插入
{
pthread_mutex_lock(&mutex);
Insert(my_rand(&seed) % MAX_KEY);
pthread_mutex_unlock(&mutex);
my_insert++;
}
else// 随机数大于搜索和插入的概率,执行删除操作
{
pthread_mutex_lock(&mutex);
Delete(my_rand(&seed) % MAX_KEY);
pthread_mutex_unlock(&mutex);
my_delete++;
}
}
pthread_mutex_lock(&count_mutex);// 将操作数加入总计数据中
member_total += my_member;
insert_total += my_insert;
delete_total += my_delete;
pthread_mutex_unlock(&count_mutex);
return NULL;
} int main(int argc, char* argv[])
{
int i, attempts, inserts_in_main;
unsigned seed = ;
pthread_t *thread_handles;
if (argc != ) Usage(argv[]);
thread_count = strtol(argv[], NULL, );
Get_input(&inserts_in_main); for (i = attempts = ; i < inserts_in_main && attempts < * inserts_in_main; attempts++)// 尝试先插入 2 * inserts_in_main 个结点
{
if (Insert(my_rand(&seed) % MAX_KEY))
i++;
}
printf("Inserted %ld keys in empty list\n", i);
# ifdef OUTPUT
printf("Before starting threads, list = \n");
Print();
printf("\n");
# endif
thread_handles = malloc(thread_count * sizeof(pthread_t));
pthread_mutex_init(&mutex, NULL);
pthread_mutex_init(&count_mutex, NULL);
for (i = ; i < thread_count; i++)
pthread_create(&thread_handles[i], NULL, Thread_work, (void*)i);
for (i = ; i < thread_count; i++)
pthread_join(thread_handles[i], NULL);
printf("Total ops = %d\n", total_ops);
printf("member ops = %d\n", member_total);
printf("insert ops = %d\n", insert_total);
printf("delete ops = %d\n", delete_total);
# ifdef OUTPUT
printf("After threads terminate, list = \n");
Print();
printf("\n");
# endif
Free_list();
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&count_mutex);
free(thread_handles);
return ;
}

● 代码,使用多互斥量,每个结点一个互斥量

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "my_rand.h" const int MAX_KEY = ;
const int IN_LIST = ;
const int EMPTY_LIST = -;
const int END_OF_LIST = ; struct list_node_s// 重新定义了单链表结点,每个结点增加一个互斥量
{
int data;
pthread_mutex_t mutex;
struct list_node_s* next;
}; struct list_node_s* head = NULL;
pthread_mutex_t head_mutex;
int thread_count;
int total_ops;
double insert_percent;
double search_percent;
double delete_percent;
pthread_mutex_t count_mutex;
int member_total = , insert_total = , delete_total = ; void Usage(char* prog_name)
{
fprintf(stderr, "usage: %s <thread_count>\n", prog_name);
exit();
} void Get_input(int* inserts_in_main_p)
{
printf("How many keys should be inserted in the main thread?\n");
scanf("%d", inserts_in_main_p);
printf("How many total ops should be executed?\n");
scanf("%d", &total_ops);
printf("Percent of ops that should be searches? (between 0 and 1)\n");
scanf("%lf", &search_percent);
printf("Percent of ops that should be inserts? (between 0 and 1)\n");
scanf("%lf", &insert_percent);
delete_percent = 1.0 - (search_percent + insert_percent);
} void Init_ptrs(struct list_node_s** curr_pp, struct list_node_s** pred_pp)// 初始化结点指针对 *curr_pp 和 *pred_pp
{
*pred_pp = NULL;
pthread_mutex_lock(&head_mutex);
*curr_pp = head;
if (*curr_pp != NULL)
pthread_mutex_lock(&((*curr_pp)->mutex));
// pthread_mutex_unlock(&head_mutex);
return;
} int Advance_ptrs(struct list_node_s** curr_pp, struct list_node_s** pred_pp)// 将结点指针 *curr_pp 和 *pred_pp 向后移动一格
{
struct list_node_s* curr_p = *curr_pp, *pred_p = *pred_pp;
if (curr_p == NULL)
{
if (pred_p == NULL)
{
pthread_mutex_unlock(&head_mutex);
return EMPTY_LIST;
}
else
return END_OF_LIST;
}
if (curr_p->next != NULL)
pthread_mutex_lock(&(curr_p->next->mutex));
if (pred_p != NULL)
pthread_mutex_unlock(&(pred_p->mutex));
else
pthread_mutex_unlock(&head_mutex);
*pred_pp = curr_p, *curr_pp = curr_p->next;
return (curr_p->next == NULL) ? END_OF_LIST : IN_LIST;
} int Insert(int value)
{
struct list_node_s *curr, *pred, *temp;
for (Init_ptrs(&curr, &pred); curr != NULL && curr->data < value; Advance_ptrs(&curr, &pred));
if (curr == NULL || curr->data > value)
{
# ifdef DEBUG
printf("Inserting %d\n", value);
# endif
temp = malloc(sizeof(struct list_node_s));
pthread_mutex_init(&(temp->mutex), NULL);
temp->data = value;
temp->next = curr;
if (curr != NULL)
pthread_mutex_unlock(&(curr->mutex));
if (pred == NULL)
{
head = temp;
pthread_mutex_unlock(&head_mutex);
}
else
{
pred->next = temp;
pthread_mutex_unlock(&(pred->mutex));
}
return ;
}
if (curr != NULL)
pthread_mutex_unlock(&(curr->mutex));
if (pred != NULL)
pthread_mutex_unlock(&(pred->mutex));
else
pthread_mutex_unlock(&head_mutex);
return ;
} void Print(void)// 注意不使用互斥量
{
struct list_node_s *temp;
printf("list = ");
for (temp = head; temp != (struct list_node_s*) NULL; temp = temp->next)
printf("%d ", temp->data);
printf("\n");
} int Member(int value)
{
struct list_node_s *temp, *old_temp;
pthread_mutex_lock(&head_mutex);
if (head != NULL)
pthread_mutex_lock(&(head->mutex));
pthread_mutex_unlock(&head_mutex);
for (temp = head; temp != NULL && temp->data < value;)
{
if (temp->next != NULL)
pthread_mutex_lock(&(temp->next->mutex));
old_temp = temp;
temp = temp->next;
pthread_mutex_unlock(&(old_temp->mutex));
}
if (temp == NULL || temp->data > value)
{
# ifdef DEBUG
printf("%d is not in the list\n", value);
# endif
if (temp != NULL)
pthread_mutex_unlock(&(temp->mutex));
return ;
}
# ifdef DEBUG
printf("%d is in the list\n", value);
# endif
pthread_mutex_unlock(&(temp->mutex));
return ;
} int Delete(int value)
{
struct list_node_s *curr, *pred;
for (Init_ptrs(&curr, &pred); curr != NULL && curr->data < value; Advance_ptrs(&curr, &pred));
if (curr != NULL && curr->data == value)
{
if (pred == NULL)
{
head = curr->next;
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
pthread_mutex_unlock(&head_mutex);
pthread_mutex_unlock(&(curr->mutex));
pthread_mutex_destroy(&(curr->mutex));
free(curr);
}
else
{
pred->next = curr->next;
pthread_mutex_unlock(&(pred->mutex));
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
pthread_mutex_unlock(&(curr->mutex));
pthread_mutex_destroy(&(curr->mutex));
free(curr);
}
return ;
}
if (pred != NULL)
pthread_mutex_unlock(&(pred->mutex));
if (curr != NULL)
pthread_mutex_unlock(&(curr->mutex));
if (curr == head)
pthread_mutex_unlock(&head_mutex);
return ;
} int Is_empty(void)
{
return head == NULL;
} void Free_list(void)
{
struct list_node_s *current, *following;
if (Is_empty())
return;
for (current = head, following = current->next; following != NULL; free(current), current = following, following = current->next)
{
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
}
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
free(current);
} void* Thread_work(void* rank)
{
unsigned seed = (long)rank + ;
int i, my_member, my_insert, my_delete;
double which_op;
for (i = my_member = my_insert = my_delete = ; i < total_ops / thread_count; i++)
{
which_op = my_drand(&seed);
if (which_op < search_percent)
{
# ifdef DEBUG
printf("Thread %ld > Searching for %d\n", my_rank, val);
# endif
Member(my_rand(&seed) % MAX_KEY);
my_member++;
}
else if (which_op < search_percent + insert_percent)
{
# ifdef DEBUG
printf("Thread %ld > Attempting to insert %d\n", my_rank, val);
# endif
Insert(my_rand(&seed) % MAX_KEY);
my_insert++;
}
else
{
# ifdef DEBUG
printf("Thread %ld > Attempting to delete %d\n", my_rank, val);
# endif
Delete(my_rand(&seed) % MAX_KEY);
my_delete++;
}
}
pthread_mutex_lock(&count_mutex);
member_total += my_member;
insert_total += my_insert;
delete_total += my_delete;
pthread_mutex_unlock(&count_mutex);
return NULL;
} int main(int argc, char* argv[])
{
int i, attempts, inserts_in_main;
unsigned seed = ;
pthread_t* thread_handles;
if (argc != ) Usage(argv[]);
thread_count = strtol(argv[], NULL, );
Get_input(&inserts_in_main); for (i = attempts = ; i < inserts_in_main && attempts < * inserts_in_main; attempts++)
{
if (Insert(my_rand(&seed) % MAX_KEY))
i++;
}
printf("Inserted %ld keys in empty list\n", i);
# ifdef OUTPUT
printf("Before starting threads, list = \n");
Print();
printf("\n");
# endif
thread_handles = malloc(thread_count * sizeof(pthread_t));
pthread_mutex_init(&head_mutex, NULL);
pthread_mutex_init(&count_mutex, NULL);
for (i = ; i < thread_count; i++)
pthread_create(&thread_handles[i], NULL, Thread_work, (void*)i);
for (i = ; i < thread_count; i++)
pthread_join(thread_handles[i], NULL);
printf("Total ops = %d\n", total_ops);
printf("member ops = %d\n", member_total);
printf("insert ops = %d\n", insert_total);
printf("delete ops = %d\n", delete_total);
# ifdef OUTPUT
printf("After threads terminate, list = \n");
Print();
printf("\n");
# endif
Free_list();
pthread_mutex_destroy(&head_mutex);
pthread_mutex_destroy(&count_mutex);
free(thread_handles);
return ;
}

● 代码,使用读写锁

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "my_rand.h" const int MAX_KEY = ; struct list_node_s
{
int data;
struct list_node_s* next;
}; struct list_node_s *head = NULL;
int thread_count;
int total_ops;
double insert_percent;
double search_percent;
double delete_percent;
pthread_rwlock_t rwlock; // 读写锁
pthread_mutex_t count_mutex;
int member_total = , insert_total = , delete_total = ; void Usage(char* prog_name)
{
fprintf(stderr, "usage: %s <thread_count>\n", prog_name);
exit();
} void Get_input(int* inserts_in_main_p)
{
printf("How many keys should be inserted in the main thread?\n");
scanf("%d", inserts_in_main_p);
printf("How many total ops should be executed?\n");
scanf("%d", &total_ops);
printf("Percent of ops that should be searches? (between 0 and 1)\n");
scanf("%lf", &search_percent);
printf("Percent of ops that should be inserts? (between 0 and 1)\n");
scanf("%lf", &insert_percent);
delete_percent = 1.0 - (search_percent + insert_percent);
} int Insert(int value)
{
struct list_node_s *curr, *pred = NULL, *temp;
for (curr = head, pred = NULL; curr != NULL && curr->data < value; pred = curr, curr = curr->next);
if (curr == NULL || curr->data > value)
{
temp = malloc(sizeof(struct list_node_s));
temp->data = value;
temp->next = curr;
if (pred == NULL)
head = temp;
else
pred->next = temp;
return ;
}
return ;
} void Print(void)
{
struct list_node_s *temp;
printf("list = ");
for (temp = head; temp != (struct list_node_s*) NULL; temp = temp->next)
printf("%d ", temp->data);
printf("\n");
} int Member(int value)
{
struct list_node_s *temp;
for (temp = head; temp != NULL && temp->data < value; temp = temp->next);
if (temp == NULL || temp->data > value)
{
# ifdef DEBUG
printf("%d is not in the list\n", value);
# endif
return ;
}
# ifdef DEBUG
printf("%d is in the list\n", value);
# endif
return ;
} int Delete(int value)
{
struct list_node_s *curr, *pred;
for (curr = head, pred = NULL; curr != NULL && curr->data < value; pred = curr, curr = curr->next);
if (curr != NULL && curr->data == value)
{
if (pred == NULL)
head = curr->next;
else
pred->next = curr->next;
# ifdef DEBUG
printf("Freeing %d\n", value);
# endif
free(curr);
return ;
}
return ;
} int Is_empty(void)
{
return head == NULL;
} void Free_list(void)
{
struct list_node_s *current, *following;
if (Is_empty())
return;
for (current = head, following = current->next; following != NULL; free(current), current = following, following = current->next)
{
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
}
# ifdef DEBUG
printf("Freeing %d\n", current->data);
# endif
free(current);
} void* Thread_work(void* rank)
{
int i, my_member, my_insert, my_delete;
unsigned seed = (long)rank + ;
double which_op;
for (i = my_member = my_insert = my_delete = ; i < total_ops / thread_count; i++)
{
which_op = my_drand(&seed);
if (which_op < search_percent)
{
pthread_rwlock_rdlock(&rwlock);
Member(my_rand(&seed) % MAX_KEY);
pthread_rwlock_unlock(&rwlock);
my_member++;
}
else if (which_op < search_percent + insert_percent)
{
pthread_rwlock_wrlock(&rwlock);
Insert(my_rand(&seed) % MAX_KEY);
pthread_rwlock_unlock(&rwlock);
my_insert++;
}
else
{
pthread_rwlock_wrlock(&rwlock);
Delete(my_rand(&seed) % MAX_KEY);
pthread_rwlock_unlock(&rwlock);
my_delete++;
}
}
pthread_mutex_lock(&count_mutex);
member_total += my_member;
insert_total += my_insert;
delete_total += my_delete;
pthread_mutex_unlock(&count_mutex);
return NULL;
} int main(int argc, char* argv[])
{
int i, attempts, inserts_in_main;
unsigned seed = ;
pthread_t *thread_handles;
if (argc != ) Usage(argv[]);
thread_count = strtol(argv[], NULL, );
Get_input(&inserts_in_main); for (i = attempts = ; i < inserts_in_main && attempts < * inserts_in_main; attempts++)
{
if (Insert(my_rand(&seed) % MAX_KEY))
i++;
}
printf("Inserted %ld keys in empty list\n", i);
# ifdef OUTPUT
printf("Before starting threads, list = \n");
Print();
printf("\n");
# endif
thread_handles = malloc(thread_count * sizeof(pthread_t));
pthread_mutex_init(&count_mutex, NULL);
pthread_rwlock_init(&rwlock, NULL);
for (i = ; i < thread_count; i++)
pthread_create(&thread_handles[i], NULL, Thread_work, (void*)i);
for (i = ; i < thread_count; i++)
pthread_join(thread_handles[i], NULL);
printf("Total ops = %d\n", total_ops);
printf("member ops = %d\n", member_total);
printf("insert ops = %d\n", insert_total);
printf("delete ops = %d\n", delete_total);
# ifdef OUTPUT
printf("After threads terminate, list = \n");
Print();
printf("\n");
# endif
Free_list();
pthread_rwlock_destroy(&rwlock);
pthread_mutex_destroy(&count_mutex);
free(thread_handles);
return ;
}
上一篇:《并行程序设计导论》——OpenMP


下一篇:OpenMP并行程序设计