【线程】线程的互斥---互斥锁

线程间互斥相关概念

临界资源:多线程执行流共享的资源就叫做临界资源
临界区:每个线程内部,访问临界资源的代码,就叫做临界区
互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成,没有正在做的概念

引入锁---模拟一轮抢票

使用多线程,并发的进行抢票

下面的代码很容易看懂的

#include<iostream>
#include<vector>
#include<string>
#include<unistd.h>
#include<pthread.h>

using namespace std;

#define NUM 4
int tickets=3000;


class PtData
{
public:
    PtData(int number)
    {
        _ptname="thread-"+to_string(number);
    }

public:
    string _ptname;
};

void* GetTicket(void* args)//模拟一轮抢票
{
    PtData* td=static_cast<PtData*>(args);
    const char* name=td->_ptname.c_str();
    while(true)
    {
        if(tickets>0)
        {
            usleep(1000);
            printf("who=%s,get a ticket:%d \n",name,tickets);
            tickets--;
        }
        else break;
    }

    printf("%s....quit\n",name);
    return nullptr;
}

int main()
{
    //创建多线程
    vector<pthread_t> tids;
    vector<PtData*> pds;
    for(int i=1;i<=NUM;i++)
    {
        pthread_t tid;
        PtData* td=new PtData(i);
        pds.push_back(td);
        pthread_create(&tid,nullptr,GetTicket,td);
        tids.push_back(tid);
    }

    for(auto tid:tids)
    {
        pthread_join(tid,nullptr);
    }
    for(auto pd:pds)
    {
        delete pd;
    }
    return 0;
}

 

截取了结果的最后面,发现竟然有线程抢到了负数票,但是在我们的理解当中是不可能的啊,怎么回事呢?tickets是全局变量,它被多个线程并发访问,就会导致数据不一致问题

对一个全局变量进行--操作是否安全呢?从结果看不安全 

对tickets--,一条C语句,会被转为三条汇编语句

1.先将tickets读入到CPU的寄存器中

2.CPU内部进行--操作

3.将计算结果写回内存 

总的来说,由于线程的并发访问,线程会被切走,对全局变量计算操作汇编语句有多条,当某个线程正在执行某条的时候都有可能被切走,导致还没计算完,就有线程来访问,就会导致数据不一致问题,对全局变量计算不是原子的(原子就是做一件事,要么做完,要么不做,没有正在做的概念)

要解决以上问题,需要做到三点:
代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临界区。
如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。
要做到这三点&#

<think>嗯,用户想找一个用线程互斥算法实现点餐系统的生产者消费者模型的代码示例。首先,我需要回忆生产者消费者模型的基本结构。生产者生成订单,消费者处理订单,两者通过共享的缓冲区(比如队列)交互,这里需要互斥锁来保护共享资源,防止数据竞争。 用户提到的点餐系统,可能涉及多个生产者和消费者线程。生产者可能是顾客下单,而消费者是厨房处理订单。这时候,线程安全是关键,所以得用互斥锁,比如pthread_mutex_t。同时,可能需要条件变量pthread_cond_t来协调生产者和消费者的执行,当队列满时生产者等待,空时消费者等待。 参考引用里的资料,比如引用[1]和[4]提到互斥量mutex和lock_guard,还有阻塞队列的实现C++的例子可能用到了lock_guard,但用户可能需要C语言实现,因为点餐系统有时在Linux环境下用C。不过用户的问题没有明确语言,但之前的引用有提到C++,所以可能需要兼顾。 然后,我需要考虑代码结构。主函数创建生产者和消费者线程,使用互斥锁保护订单队列,条件变量通知状态变化。订单队列用链表或环形缓冲区实现,这里可能用STL的queue,但线程安全需要自己加锁。 需要注意的地方:互斥锁的正确初始化和销毁,条件变量的使用避免死锁。比如,当队列满时,生产者线程应等待,直到有空间;消费者取出订单后通知生产者。代码示例需要展示这些部分。 可能的问题:如何处理多个生产者和消费者?需要确保每个线程都能正确访问队列。还有,线程的同步机制,比如pthread_cond_wait必须在循环中检查条件,防止虚假唤醒。 用户可能还需要解释代码的关键部分,比如互斥锁和条件变量的作用,以及生产者消费者的工作流程。此外,性能优化方面,比如使用环形队列而不是链表,可能提升效率,但引用[2]提到了环形队列和阻塞队列的实现区别,可能需要说明。 最后,生成相关问题,比如如何扩展系统、性能优化方法、死锁处理等,帮助用户深入理解。</think>### 使用线程互斥算法实现点餐系统的生产者消费者模型 #### 1. 需求分析 点餐系统的生产者消费者模型需满足以下核心要求: - **生产者**:模拟顾客下单,生成订单并存入共享队列 - **消费者**:模拟厨房处理订单,从队列取出订单 - **线程安全**:通过互斥锁保护共享资源(订单队列) - **流量控制**:队列满时阻塞生产者,空时阻塞消费者 #### 2. C++代码实现(基于互斥锁+条件变量) ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #define MAX_ORDERS 10 // 队列最大容量 class OrderSystem { private: std::queue<int> order_queue; // 订单队列 std::mutex mtx; // 互斥锁 std::condition_variable cv_producer, cv_consumer; // 条件变量 public: // 生产者方法 void place_order(int order_id) { std::unique_lock<std::mutex> lock(mtx); cv_producer.wait(lock, [this]{ return order_queue.size() < MAX_ORDERS; }); // 队列满时等待 order_queue.push(order_id); std::cout << "生产订单: " << order_id << std::endl; cv_consumer.notify_one(); // 通知消费者 } // 消费者方法 void process_order() { std::unique_lock<std::mutex> lock(mtx); cv_consumer.wait(lock, [this]{ return !order_queue.empty(); }); // 队列空时等待 int order_id = order_queue.front(); order_queue.pop(); std::cout << "处理订单: " << order_id << std::endl; cv_producer.notify_one(); // 通知生产者 } }; // 生产者线程函数 void producer_task(OrderSystem& sys, int count) { for (int i = 1; i <= count; ++i) { sys.place_order(i); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟下单间隔 } } // 消费者线程函数 void consumer_task(OrderSystem& sys, int count) { for (int i = 1; i <= count; ++i) { sys.process_order(); std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 模拟处理耗时 } } int main() { OrderSystem system; const int total_orders = 20; std::thread producer(producer_task, std::ref(system), total_orders); std::thread consumer(consumer_task, std::ref(system), total_orders); producer.join(); consumer.join(); return 0; } ``` #### 3. 关键实现细节 1. **互斥锁保护**:通过`std::mutex`确保对订单队列的原子操作[^4] 2. **条件变量**: - `cv_producer`控制队列未满时唤醒生产者 - `cv_consumer`控制队列非空时唤醒消费者 3. **阻塞控制**: - 生产者等待条件:`order_queue.size() < MAX_ORDERS` - 消费者等待条件:`!order_queue.empty()` 4. **智能锁机制**:使用`std::unique_lock`自动管理锁生命周期,避免死锁[^4] #### 4. 运行效果示例 ``` 生产订单: 1 处理订单: 1 生产订单: 2 生产订单: 3 处理订单: 2 生产订单: 4 处理订单: 3 ... ``` #### 5. 扩展优化方向 1. **多线程扩展**:可创建多个生产者/消费者线程 2. **环形队列优化**:用固定大小数组替代`std::queue`提升性能[^2] 3. **优先级队列**:支持紧急订单优先处理 4. **死锁预防**:设置超时等待机制(`wait_for`)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱敲代码的奇点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值