C++11多线程实现的一道面试题

本文通过一个具体的C++程序示例,展示了如何使用std::mutex和std::atomic实现主线程与子线程间的精确同步控制。主线程与子线程交替运行,各自循环指定次数,确保了线程间正确有序的执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码。

这里涉及到的问题是主线程和子线程之间的切换,也就是说子线程跑一下,然后阻塞,主线程再跑一下,然后在阻塞,如此各循环 50次,注意这里的“各循环”,因为主线程和子线程各自的循环是没有关系的,而是内部各自循环50次。
这里肯定要用到std::mutex和原子操作std::atomic,主要的实现思路就是,原子变量的值符合要求,就开始循环,否则阻塞等着。
主线程代码:

for(int i = 0; i < 50; ++i) //循环50次
{
    lock_guard<mutex> lck(mt);//RAII获取锁
    if(flag % 2 == 1){  //flag的是原子变量(原子变量初值为0,所以子线程先进入循环)
        for(int i = 0; i < 100; ++i)
            cout << "parent thread: " << i << endl;
        flag++;
    }
}

子线程代码:

for(int i = 0; i < 50; ++i){
    lock_guard<mutex> lck(mt);  //RAII获取mutex
    if(flag % 2 == 0){  //子线程运行区域
        for(int i = 0; i < 10; ++i)
            cout << "child thread: " << i << endl;
        flag++;
    }
}

完整代码如下:

#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
using namespace std;
mutex mt;   //互斥量
atomic<int> flag = 0;   //原子变量
void func()
{
    for(int i = 0; i < 50; ++i){
        lock_guard<mutex> lck(mt);  //RAII获取mutex
        if(flag % 2 == 0){  //子线程运行区域
            for(int i = 0; i < 10; ++i)
                cout << "child thread: " << i << endl;
            flag++;
        }
    }
}
int main()
{
    thread t1(func);
    for(int i = 0; i < 50; ++i)
    {
        lock_guard<mutex> lck(mt);
        if(flag % 2 == 1){  //主线程运行区域
            for(int i = 0; i < 100; ++i)
                cout << "parent thread: " << i << endl;
            flag++;
        }
    }

    t1.join();

    return 0;
}
### C++11 多线程编程常见面试问题 #### 1. 如何创建线程并管理其生命周期? C++11 提供了 `std::thread` 来创建和管理线程。通过构造 `std::thread` 对象并传入可调用对象(如函数指针、Lambda 表达式、函数对象、`std::bind` 表达式等)来启动新线程。线程的生命周期可以通过 `join()` 或 `detach()` 来管理。调用 `join()` 会阻塞主线程,直到新线程执行完毕;而 `detach()` 则将线程设置为后台运行,主线程不再等待其完成。 ```cpp #include <iostream> #include <thread> void thread_func() { std::cout << "Hello from thread!" << std::endl; } int main() { std::thread t(thread_func); t.join(); // 等待线程完成 return 0; } ``` #### 2. 多线程中如何保护共享数据? 多线程访问共享数据时,必须使用同步机制来避免数据竞争和不一致问题。常见的同步工具包括互斥锁(`std::mutex`)、条件变量(`std::condition_variable`)和原子操作(`std::atomic`)。使用 `std::lock_guard` 或 `std::unique_lock` 可以自动管理锁的获取和释放,确保线程安全[^2]。 ```cpp #include <iostream> #include <thread> #include <mutex> std::mutex mtx; int shared_data = 0; void increment() { for (int i = 0; i < 100000; ++i) { std::lock_guard<std::mutex> lock(mtx); ++shared_data; } } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Shared data: " << shared_data << std::endl; return 0; } ``` #### 3. 如何使用条件变量实现线程间通信? 条件变量(`std::condition_variable`)用于线程间的通知机制。一个线程等待某个条件成立,另一个线程在条件满足时通知等待的线程继续执行。通常与互斥锁配合使用,确保线程安全。 ```cpp #include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void wait_for_ready() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); std::cout << "Thread is ready!" << std::endl; } void set_ready() { std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard<std::mutex> lock(mtx); ready = true; } cv.notify_one(); } int main() { std::thread t1(wait_for_ready); std::thread t2(set_ready); t1.join(); t2.join(); return 0; } ``` #### 4. 如何使用信号量实现线程同步? 信号量(`sem_t`)是一种用于线程同步的计数器,常用于控制对共享资源的访问。在 C++11 中,虽然标准库没有直接提供信号量,但可以通过封装 POSIX 信号量(`sem_init`、`sem_wait`、`sem_post`)来实现线程同步。 ```cpp #include <iostream> #include <thread> #include <semaphore.h> sem_t sem; void thread_func() { sem_wait(&sem); std::cout << "Thread is running." << std::endl; sem_post(&sem); } int main() { sem_init(&sem, 0, 1); std::thread t1(thread_func); std::thread t2(thread_func); t1.join(); t2.join(); sem_destroy(&sem); return 0; } ``` #### 5. 如何确保线程安全地访问共享内存? 在共享内存的多线程访问中,需要结合互斥锁或信号量来保护共享资源。例如,在使用 Boost.Interprocess 或系统调用(如 `shmget` 和 `shmat`)创建的共享内存中,可以使用 `boost::interprocess::named_mutex` 或 `std::mutex` 来确保线程安全。 ```cpp #include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/named_mutex.hpp> #include <iostream> int main() { using namespace boost::interprocess; shared_memory_object shm(open_or_create, "MySharedMemory", read_write); shm.truncate(1024); mapped_region region(shm, read_write); char* mem = static_cast<char*>(region.get_address()); named_mutex mutex(open_or_create, "MyMutex"); mutex.lock(); std::strcpy(mem, "Hello from shared memory!"); std::cout << mem << std::endl; mutex.unlock(); return 0; } ``` #### 6. 如何实现线程池? 线程池是一种管理多个线程的机制,用于减少线程创建和销毁的开销。可以通过任务队列和多个工作线程实现线程池。任务队列通常使用互斥锁和条件变量进行同步。 ```cpp #include <iostream> #include <thread> #include <vector> #include <queue> #include <functional> #include <mutex> #include <condition_variable> class ThreadPool { public: ThreadPool(size_t num_threads) { for (size_t i = 0; i < num_threads; ++i) { workers.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(queue_mutex); condition.wait(lock, [this] { return stop || !tasks.empty(); }); if (stop && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } task(); } }); } } template<class F> void enqueue(F&& task) { { std::unique_lock<std::mutex> lock(queue_mutex); tasks.emplace(std::forward<F>(task)); } condition.notify_one(); } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queue_mutex); stop = true; } condition.notify_all(); for (std::thread& worker : workers) worker.join(); } private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值