博客
关于我
Linux —— 线程互斥
阅读量:806 次
发布时间:2023-02-01

本文共 3872 字,大约阅读时间需要 12 分钟。

Linux 线程互斥

线程封装

为了简化 POSIX 线程 (pthread) 的使用,我们可以自定义一个线程封装类 MyThread。该类通过提供线程的启动和控制功能,使得线程的创建更加面向对象和便捷。

类定义

class MyThread {    public:        MyThread(pthread_t tid, const std::string &name, func_t func)            : _tid(tid), _name(name), _isrunning(false), _fun(func) {            std::cout << "My tid is " << _tid << " name is " << _name << std::endl;        }        ~MyThread() {} // 孤立        static void *ThreadRoutine(void *args) {            MyThread *th = static_cast
(args); th->_fun(); return nullptr; } void Start() { int retValue = pthread_create(&_tid, nullptr, ThreadRoutine, this); if (retValue != 0) { std::cout << "Create thread failed! Error code: " << retValue << std::endl; return; } else { _isrunning = true; std::cout << "Thread started successfully." << std::endl; } } void Join() { if (!_isrunning) return; int retValue = pthread_join(_tid, nullptr); if (retValue == 0) { _isrunning = false; } else { std::cout << "Join failed! Error code: " << retValue << std::endl; } } private: pthread_t _tid; std::string _name; bool _isrunning; func_t _fun;};

使用例子

#include "thread.hpp"void Print() {    std::cout << "Step in" << std::endl;    while (true) {        std::cout << "I am running" << std::endl;        sleep(1);    }}int cnt = 0;std::string GetName() {    std::string name = "thread : " + std::to_string(cnt);    cnt++;    return name;}int main() {    pthread_t tid = 0;    MyThread th(tid, GetName(), Print);    th.Start();    th.Join();    return 0;}

注意事项

  • 静态成员函数ThreadRoutine 必须是静态的,因为它作为线程入口点,不能持有 MyThread 实例。
  • 参数传递Start 方法将 this 作为参数传递给 pthread_create,允许线程实例在静态成员函数中访问自身的成员。
  • 线程结束:使用 Join 方法等待线程结束,并正确释放资源。

线程互斥

多个线程同时访问公共资源(临界区域)可能导致竞态条件(Race Condition),导致数据一致性问题。解决方法是使用互斥锁(Mutex)。

模拟抢票问题

#include 
#include
#include
int ticket = 100;void *route(void *arg) { char *id = (char *)arg; while (1) { pthread_mutex_lock(nullptr); if (ticket > 0) { usleep(1000); printf("%s sells ticket %d\n", id, ticket); ticket--; } else { pthread_mutex_unlock(nullptr); break; } } return nullptr;}int main() { pthread_t t1, t2, t3, t4; pthread_create(&t1, nullptr, route, (void *)"thread 1"); pthread_create(&t2, nullptr, route, (void *)"thread 2"); pthread_create(&t3, nullptr, route, (void *)"thread 3"); pthread_create(&t4, nullptr, route, (void *)"thread 4"); pthread_join(t1, nullptr); pthread_join(t2, nullptr); pthread_join(t3, nullptr); pthread_join(t4, nullptr); return 0;}

解释

  • 互斥锁:确保只有一个线程可以访问 ticket,防止票被多次购买。
  • 线程启动:使用 pthread_create 创建四个售票线程。
  • 等待线程:使用 pthread_join 等待所有线程完成操作。

优化票卖逻辑

void *route(void *arg) {    char *id = static_cast
(arg); while (1) { pthread_mutex_lock(&mutex); if (ticket > 0) { sleep(1); // 模拟购票耗时 printf("%s sells ticket %d\n", id, ticket); ticket--; } pthread_mutex_unlock(&mutex); if (ticket <= 0) { break; } } return nullptr;}

###Linux下的互斥锁接口

在 Linux 中,互斥锁接口包括以下函数:

  • pthread_mutex_init(pthread_mutex_t mutex, const pthread_mutexattr_t *):初始化互斥锁。
  • pthread_mutex_destroy(pthread_mutex_t mutex):销毁互斥锁。
  • pthread_mutex_lock(pthread_mutex_t mutex):锁定互斥锁。
  • pthread_mutex_trylock(pthread_mutex_t mutex):非阻塞锁定互斥锁。
  • pthread_mutex_unlock(pthread_mutex_t mutex):解锁互斥锁。
  • pthread_mutexattr_init(pthread_mutexattr_t *attr):初始化互斥锁属性。
  • pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type):设置互斥锁属性类型。

结论

通过使用互斥锁,可以有效地保护共享资源,防止竞态条件。掌握这些知识对于开发安全的多线程程序至关重要,确保程序稳定运行。

转载地址:http://kpwfk.baihongyu.com/

你可能感兴趣的文章
Netty工作笔记0025---SocketChannel API
查看>>
Netty工作笔记0027---NIO 网络编程应用--群聊系统2--服务器编写2
查看>>
Netty工作笔记0028---NIO 网络编程应用--群聊系统3--客户端编写1
查看>>
Netty工作笔记0034---Netty架构设计--线程模型
查看>>
Netty工作笔记0050---Netty核心模块1
查看>>
Netty工作笔记0057---Netty群聊系统服务端
查看>>
Netty工作笔记0060---Tcp长连接和短连接_Http长连接和短连接_UDP长连接和短连接
查看>>
Netty工作笔记0063---WebSocket长连接开发2
查看>>
Netty工作笔记0070---Protobuf使用案例Codec使用
查看>>
Netty工作笔记0072---Protobuf内容小结
查看>>
Netty工作笔记0074---handler链调用机制实例1
查看>>
Netty工作笔记0077---handler链调用机制实例4
查看>>
Netty工作笔记0081---编解码器和处理器链梳理
查看>>
Netty工作笔记0083---通过自定义协议解决粘包拆包问题1
查看>>
Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
查看>>
Netty工作笔记0085---TCP粘包拆包内容梳理
查看>>
Netty常用组件一
查看>>
Netty常见组件二
查看>>
netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
查看>>
Netty心跳检测
查看>>