Go 和 C++ 中线程的区别

问题描述 投票:0回答:1

我有这个线程安全队列(在

GoLang
Cpp
中实现),我在其中生成超过 100K 线程以将数据推送到共享队列中。在我的笔记本电脑上,我有 8 个核心和 16 个逻辑处理器以及 16GB RAM。

我在

Go
C++
上编写了相同的程序。在我的个人机器上,程序在
Go
中的大量线程下运行良好,但是当我使用
cpp
执行程序时,程序崩溃了,我得到
segmentation fault
。我明白这是因为我有 8 个核心,但我正在产生大量线程。但我不明白的是
Go
如何处理这种情况以及为什么
Cpp
没有配置为以相同的方式处理这种情况?

在内部处理线程方面,

Go
C++
有何不同?

GoLang
中的以下代码适用于 100K 或以上线程。然而 C++ 甚至无法处理 5K 线程。

Go语言

package main

import (
    "fmt"
    "math/rand"
    "sync"
)

type ConcurrentQueue struct {
    queue []int32
    lock  sync.Mutex
}

func (q *ConcurrentQueue) Enqueue(item int32) {
    q.lock.Lock()
    defer q.lock.Unlock()
    q.queue = append(q.queue, item)
}

func (q *ConcurrentQueue) Dequeue() int32 {
    q.lock.Lock()
    defer q.lock.Unlock()

    if len(q.queue) == 0 {
        panic("removing from an empty queue")
    }
    item := q.queue[0]
    q.queue = q.queue[1:]
    return item
}

func (q *ConcurrentQueue) Size() int {
    q.lock.Lock()
    defer q.lock.Unlock()
    return len(q.queue)
}

const NUM_THREADS int = 100000

func main() {
    queue := &ConcurrentQueue{
        queue: make([]int32, 0),
    }

    var wgE sync.WaitGroup
    var wgD sync.WaitGroup

    fmt.Println("size before enqueue:", queue.Size())
    for i := 0; i < NUM_THREADS; i++ {
        wgE.Add(1)
        go func() {
            queue.Enqueue(rand.Int31())
            wgE.Done()
        }()
    }

    wgE.Wait()
    fmt.Println("size after enqueue:", queue.Size())

    for i := 0; i < NUM_THREADS; i++ {
        wgD.Add(1)
        go func() {
            queue.Dequeue()
            wgD.Done()
        }()
    }

    wgD.Wait()

    fmt.Println("size after dequeue:", queue.Size())
}

输出:

size before enqueue: 0
size after enqueue: 100000
size after dequeue: 0

以下 C++ 代码在 100K 线程时出现分段错误

C++

#include <iostream>
#include <queue>
#include <cstdlib>
#include <thread>
#include <mutex>
#include <condition_variable>

class ThreadSafeQueue
{
    private:
    std::queue<int> q;
    std::mutex qMutex;  
    std::condition_variable m_cond;
    public:
    ThreadSafeQueue() { }
    ThreadSafeQueue(const ThreadSafeQueue &) = delete ;
    ThreadSafeQueue& operator=(const ThreadSafeQueue &) = delete ;
    
    void Enqueue(int val);
    void Dequeue();
    size_t Size();
};

void ThreadSafeQueue::Enqueue(int val)
{
    std::lock_guard<std::mutex> guard(qMutex);
    q.push(val);
}

void ThreadSafeQueue::Dequeue()
{   
    std::unique_lock<std::mutex> lock(qMutex);

    m_cond.wait(lock, [this] {  return !q.empty(); }); 
    
    q.pop();
}

size_t ThreadSafeQueue::Size()
{
    return q.size();
}

void UpdateQueue(ThreadSafeQueue &qObj, int val)
{
    qObj.Enqueue(val);
}
void DeleteQueue(ThreadSafeQueue &qObj)
{
    qObj.Dequeue();
}

int main()
{
    int N;
    ThreadSafeQueue qObj;
    std::cout<<"How many values do you want to insert"<<std::endl;
    std::cin>>N;
    std::cout<<"Before inserting size of queue is "<<qObj.Size()<<std::endl;

    
    std::vector<std::thread> threads;
    for(int i = 0; i < N; i++)
    {
        threads.push_back(std::thread(UpdateQueue, std::ref(qObj), rand()));
    }

    for (auto& th : threads) th.join();
    threads.clear();
        
    std::cout<<"After inserting size of queue is "<<qObj.Size() <<std::endl;
    std::cout<<"Dequeuing using threads"<<std::endl;
    
    for(int i = 0; i < N; i++)
    {
        threads.push_back(std::thread(DeleteQueue, std::ref(qObj)));
    }
    for (auto& th : threads) th.join();
    std::cout<<"After dequeing size of queue is "<<qObj.Size()<<std::endl;
}

c++ multithreading go locking mutex
1个回答
1
投票

我不明白Go是如何处理这种情况的

在 Golang 中,实际系统线程和代码之间有一个层,即运行时调度程序。该调度程序保留一个实际操作系统线程的线程池,用于执行线程代码。

为什么 Cpp 没有配置为以相同的方式处理这种情况?

因为C++线程是操作系统线程。如果需要,您必须创建一个线程池 - 或者使用协程或异步 - 或执行策略。

© www.soinside.com 2019 - 2024. All rights reserved.