繁体   English   中英

无法在 C 中使用 OpenMP 实现 Dijkstra 算法

[英]Unable to implement Dijkstra's Algorithm using OpenMP in C

我正在尝试使用 OpenMP 并行化 Dijkstra,但该程序无法正常运行。 有时会显示正确的结果,而有时我会得到错误的值,我认为这是因为多个线程正在更新同一个变量。 但是我找不到这个问题的根源,因为我在关键区域内进行共享变量更新。 有人可以帮我确定我的任务是什么错误吗?这个代码在概念上是正确的吗?

int minDistance(int s,int e,int dist[], bool sptSet[])
{
    // Initialize min value
    int mini = INT_MAX, min_index;

    for (int v = s; v <= e; v++){
        if (sptSet[v] == false && dist[v] < mini){
            mini = dist[v];
    
            min_index = v;
        }
        //printf("min_ind %d\n",min_index);
    }
    return min_index;
}

void Update(int graph[V][V],int s,int e,int hold,int dist[], bool sptSet[]){

    for (int v = s; v <= e; v++){

        // Update dist[v] only if is not in sptSet,
        // there is an edge from u to v, and total
        // weight of path from src to  v through u is
        // smaller than current value of dist[v]
        if (!sptSet[v] && graph[hold][v] && dist[hold] != INT_MAX && dist[hold] + graph[hold][v] < dist[v]){
                
            dist[v] = dist[hold] + graph[hold][v];
        }
    }
}
void dijkstra(int graph[V][V],int src)
{
    int dist[V]; // The output array.  dist[i] will hold the
                 // shortest
    // distance from src to i
    
    bool sptSet[V]; // sptSet[i] will be true if vertex i is
                    // included in shortest
    // path tree or shortest distance from src to i is
    // finalized
 
    // Initialize all distances as INFINITE and stpSet[] as
    // false

    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX, sptSet[i] = false;
 
    // Distance of source vertex from itself is always 0
    dist[src] = 0;
    int min;
    int hold;
    int u;

    // Find shortest path for all vertices
    float start = omp_get_wtime();

#pragma omp parallel shared(hold) private(u) num_threads(3)
    {
        min=INT_MAX;
        int x = omp_get_num_threads();
   
        int chunk = V/x;

        int me = omp_get_thread_num();

        int startv = me * chunk; 
        int endv = startv + chunk - 1;
        int count = 0;

        for (count = 0; count < V - 1; count++) {
            // Pick the minimum distance vertex from the set of
            // vertices not yet processed. u is always equal to
            // src in the first iteration.

            u = minDistance(startv,endv,dist, sptSet);

            //updating overall minimum
#pragma omp critical
            {
                if(min > dist[u]){
                    min = dist[u];
                    hold = u;
                }
            }
            //waiting for all threads to execute critical section bfr proceeding
    #pragma omp barrier
            // Mark the picked vertex as processed
    
        #pragma omp single
            {
                sptSet[hold] = true;
            }
    #pragma omp barrier

            // Update dist value of the adjacent vertices of the
            // picked vertex.
            Update(graph,startv,endv,hold,dist,sptSet);

            min = INT_MAX;
        }
    }

    float end = omp_get_wtime();
    // print the constructed distance array
    printSolution(dist);
    printf("Running time: %f ms\n", (end - start)*1000);
}

--------------序列号:--------------------

int minDistance(int dist[], bool sptSet[])
{
    // Initialize min value
    int min = INT_MAX, min_index;
     
    for (int v = 0; v < V; v++)
        if (sptSet[v] == false && dist[v] <= min)
            min = dist[v], min_index = v;
     
    return min_index;
}
     
// A utility function to print the constructed distance
// array
void printSolution(int dist[])
{
    printf("Vertex \t\t Distance from Source\n");
    for (int i = 0; i < V; i++)
        printf("%d \t\t\t\t %d\n", i, dist[i]);
}
     
// Function that implements Dijkstra's single source
// shortest path algorithm for a graph represented using
// adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
    int dist[V]; // The output array.  dist[i] will hold the
                 // shortest
        // distance from src to i
     
    bool sptSet[V]; // sptSet[i] will be true if vertex i is
                    // included in shortest
    // path tree or shortest distance from src to i is
    // finalized
     
    // Initialize all distances as INFINITE and stpSet[] as
    // false
    for (int i = 0; i < V; i++)
        dist[i] = INT_MAX, sptSet[i] = false;
     
    // Distance of source vertex from itself is always 0
    dist[src] = 0;
     
    // Find shortest path for all vertices
    for (int count = 0; count < V - 1; count++) {
        // Pick the minimum distance vertex from the set of
        // vertices not yet processed. u is always equal to
        // src in the first iteration.
        int u = minDistance(dist, sptSet);
     
        // Mark the picked vertex as processed
        sptSet[u] = true;
     
        // Update dist value of the adjacent vertices of the
        // picked vertex.
        for (int v = 0; v < V; v++)
        {
            // Update dist[v] only if is not in sptSet,
            // there is an edge from u to v, and total
            // weight of path from src to  v through u is
            // smaller than current value of dist[v]
            if (!sptSet[v] && graph[u][v]
                && dist[u] != INT_MAX
                && dist[u] + graph[u][v] < dist[v])
                dist[v] = dist[u] + graph[u][v];
        }
    }
     
    // print the constructed distance array
    printSolution(dist);
}

Dijkstra 算法是标准公式很难并行化的一个很好的算法示例。 1. 找到最小值 2. 更新其邻居的每一步都依赖于前一步。 因此,您可以做的最好的事情是 1. 将最小值变成 OpenMP 缩减 2. 将更新变成并行循环。 在小度数的图表上,这不会给你带来太大的加速。 这也意味着您的代码不正确:您正在尝试并行处理顺序的外部步骤。

但是,您不必只更新该最小点的邻居:您可以更新每一步中的所有点。 这简化了代码,并减少了开销。 它也做更多的工作,但在挂钟时间它可能完成得稍微快一些。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM