You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++多线程下二维vector原子读写线程安全问题求助

Multi-Threaded BFS Shared Matrix Synchronization Solutions

Hey there! Let's work through your multi-threaded BFS problem—this is a classic shared data synchronization issue, so let's break down each of your questions clearly, with actionable examples.


1. Can I use only std::atomic_int?

Short answer: No, not for your specific scenario. Here's why:
You have two linked pieces of data: the cost value and the nearest start vertex. Updating these two needs to be a single atomic logical operation—if you only make each int atomic, you could end up in an inconsistent state (e.g., the cost gets updated, but the nearest start doesn't, or vice versa) when threads interleave.

That said, if you did want to use std::atomic_int for individual values (maybe for a simpler single-matrix scenario), here's how you'd adjust your containers and use load()/store():

// Replace your vectors with atomic<int> versions
std::vector<std::vector<std::atomic_int>> cost_matrix;
std::vector<std::vector<std::atomic_int>> nearest_start_matrix;

// Reading a value (use memory ordering for safe cross-thread visibility)
int current_cost = cost_matrix[i][j].load(std::memory_order_acquire);

// Writing a value
cost_matrix[i][j].store(new_cost, std::memory_order_release);

But again—this doesn't solve your core problem of syncing the two matrices' updates. Skip this for your use case.


2. Should I use mutexes? Which one, and how to apply it to both datasets?

Yes, mutexes are the most straightforward and reliable solution here, especially since you're new to thread synchronization.

Which mutex to choose?

Use std::mutex paired with std::lock_guard (a RAII wrapper that automatically releases the mutex when it goes out of scope—no more forgotten unlock() calls!). Since your two matrices are tightly linked (you always update both at the same time), use a single mutex to protect both—this ensures the entire read-compare-write operation is atomic.

Example code:

First, define your shared data and mutex (either as global variables, or better yet, wrap them in a class):

#include <mutex>
#include <vector>
#include <thread>

// Shared data
std::vector<std::vector<int>> cost_matrix;
std::vector<std::vector<int>> nearest_start_matrix;
// Mutex to protect both matrices
std::mutex matrix_mutex;

Then, your BFS thread function with synchronized updates:

// Helper function to calculate new cost from your start point
int calculate_new_cost(int start_x, int start_y, int target_x, int target_y) {
    // Your BFS cost calculation logic here
    return /* computed cost */;
}

void bfs_thread(int start_x, int start_y) {
    int rows = cost_matrix.size();
    int cols = cost_matrix[0].size();

    // Your BFS traversal logic here (e.g., queue-based traversal)
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            int new_cost = calculate_new_cost(start_x, start_y, i, j);
            int new_start_id = /* Unique ID for your start point */;

            // Lock the mutex before accessing shared data
            std::lock_guard<std::mutex> lock(matrix_mutex);
            
            // Only update if new cost is lower (your core logic)
            if (new_cost < cost_matrix[i][j]) {
                cost_matrix[i][j] = new_cost;
                nearest_start_matrix[i][j] = new_start_id;
            }
        }
    }
}

To launch threads:

int main() {
    // Initialize your matrices with default values first
    cost_matrix = /* ... */;
    nearest_start_matrix = /* ... */;

    // Launch multiple BFS threads from different starts
    std::thread t1(bfs_thread, 0, 0);
    std::thread t2(bfs_thread, 5, 5);
    // ... more threads

    t1.join();
    t2.join();
    // ... join other threads

    return 0;
}

3. Should I combine atomic operations and mutexes?

No, you don't need to—mutexes already guarantee that the entire read-compare-write sequence is atomic. Adding atomic variables on top would be redundant and add unnecessary complexity.

The only edge case where this might make sense is if you had a small subset of "hot" cells that are updated constantly, but for your full-matrix BFS scenario, it's not worth the effort.


4. Other feasible solutions?

If your dataset is extremely large and mutexes cause too much thread contention (i.e., threads are waiting around for the lock too often), consider segmented mutexes (also called "sharded locks"):

  • Split your matrices into smaller, independent blocks (e.g., 2x2 blocks, or split rows into chunks)
  • Assign a separate mutex to each block
  • When updating a cell, only lock the mutex for its block

This reduces contention because threads updating cells in different blocks can run in parallel. Here's a quick example:

#include <array>
#include <mutex>

// Split matrix into 4 blocks (adjust based on your matrix size)
const int NUM_BLOCKS = 4;
std::array<std::mutex, NUM_BLOCKS> block_mutexes;

// Helper to get which block a cell belongs to
int get_block_idx(int i, int j, int total_rows, int total_cols) {
    int row_chunk = i / (total_rows / 2);
    int col_chunk = j / (total_cols / 2);
    return row_chunk * 2 + col_chunk;
}

void bfs_thread(int start_x, int start_y) {
    int rows = cost_matrix.size();
    int cols = cost_matrix[0].size();

    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            int new_cost = calculate_new_cost(start_x, start_y, i, j);
            int new_start_id = /* start point ID */;

            // Lock only the block containing this cell
            int block_idx = get_block_idx(i, j, rows, cols);
            std::lock_guard<std::mutex> lock(block_mutexes[block_idx]);

            if (new_cost < cost_matrix[i][j]) {
                cost_matrix[i][j] = new_cost;
                nearest_start_matrix[i][j] = new_start_id;
            }
        }
    }
}

Another advanced option is using lock-free structures (e.g., wrapping your cost+start pair in a struct and using std::atomic<YourStruct> with compare_exchange_strong), but this is much more complex, error-prone, and only worth it if you need maximum performance and have experience with lock-free programming.


Which solution is best for you?

  • If you're new to threading, or your dataset/thread count is moderate: Use the single mutex + std::lock_guard approach. It's simple, easy to debug, and guarantees correctness.
  • If you have a very large dataset and high thread contention: Use segmented mutexes. It balances performance and complexity better than lock-free code.

Avoid standalone std::atomic_int here—it can't sync your two linked matrices.

内容的提问来源于stack exchange,提问作者lattys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:57:36