中企动力建站怎么样,支付网站建设费用做账,做网站需要多少屏,深圳室内设计培训一、多线程不加线程互斥可能会引发的问题 下面是一个抢标逻辑。抢票为什么会抢到负数#xff1a;假设当票数为1时#xff0c;此时四个进程的判断条件tickets都大于0#xff0c;都会进入抢票操作#xff0c;第一个进程抢完票以后tickets0并写回内存#xff0c;第二个进程再…一、多线程不加线程互斥可能会引发的问题 下面是一个抢标逻辑。抢票为什么会抢到负数假设当票数为1时此时四个进程的判断条件tickets都大于0都会进入抢票操作第一个进程抢完票以后tickets0并写回内存第二个进程再从内存中读取tickets的值时此时tickets已经为0再做--就变成了-1tickets为负数就是这么来的。也就是说多线程代码如果不对共享资源做保护可能会有并发问题。
二、互斥锁
2.1、静态分配锁
如果你定义的锁是静态的或者是全局的可以直接初始化成 pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER 2.2、动态分配锁销毁锁 int pthread_mutex_init(pthread_mutex_t *restrict mutexconst pthread_mutexattr_t *restrict attr); 参数mutex要初始化的互斥量attr NULL。 int pthread_mutex_destroy(pthread_mutex_t *mutex) 注意 使用 PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁。
2.3、加锁解锁 int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); 返回值:成功返回0,失败返回错误号 。 pthread_mutex_lock函数如果申请锁成功就会继续向后运行如果申请失败该函数就会阻塞不允许继续向后运行。
加锁的粒度要越细越好。
三、加锁的底层理解 movb $0%al表示将0存入%al寄存器中%al是累加寄存器AX的低8位部分可以独立作为8位寄存器使用。 xchgb %al, mutex表示交换%al寄存器中的值和内存mutex中的值如果内存mutex中的值原本是1交换完则表示得到锁否则挂起等待。unlock中将1存入mutex内存中表示归还锁。这样无论如何得到1的线程始终只会有一个也就做到了线程互斥。 四、多线程实现简单的互斥抢票
//thread.hpp
#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include iostream
#include string
#include unistd.h
#include functional
#include pthread.hnamespace ThreadModule
{templatetypename Tusing func_t std::functionvoid(T);// typedef std::functionvoid(const T) func_t;templatetypename Tclass Thread{public:void Excute(){_func(_data);}public:Thread(func_tT func, T data, const std::string namenone-name): _func(func), _data(data), _threadname(name), _stop(true){}//记住此方法static void *threadroutine(void *args) // 类成员函数形参是有this指针的{ThreadT *self static_castThreadT *(args);self-Excute();return nullptr;}bool Start(){int n pthread_create(_tid, nullptr, threadroutine, this);if(!n){_stop false;return true;}else{return false;}}void Detach(){if(!_stop){pthread_detach(_tid);}}void Join(){if(!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop true;}~Thread() {}private:pthread_t _tid;std::string _threadname;T _data;func_tT _func;bool _stop;};
} #endif
//LockGuard.hpp
#ifndef __LOCK_GUARD_HPP__
#define __LOCK_GUARD_HPP__#include iostream
#include pthread.hclass LockGuard
{
private:pthread_mutex_t* _mutex;
public:LockGuard( pthread_mutex_t* mutex):_mutex(mutex){pthread_mutex_lock(_mutex);}~LockGuard(){pthread_mutex_unlock(_mutex);}};#endif
//testThread.cc
#include iostream
#include vector
#include LockGuard.hpp
#include Thread.hpp
using namespace ThreadModule;int g_tickets 10000;
const int num 4;class ThreadData
{
public:int _tickets; // 所有的线程最后都会引用同一个全局的g_ticketsstd::string _name;int _total;pthread_mutex_t _mutex;public:ThreadData(int tickets, const std::string name, pthread_mutex_t mutex): _tickets(tickets), _name(name), _total(0), _mutex(mutex){}~ThreadData(){}
};void route(ThreadData *td)
{while (true){LockGuard guard(td-_mutex);if (td-_tickets 0){usleep(1000);printf(%s running, get tickets: %d\n, td-_name.c_str(), td-_tickets); td-_tickets--; td-_total;}elsebreak;}
}int main()
{pthread_mutex_t mutex;pthread_mutex_init(mutex,nullptr);std::vectorThreadThreadData* threads;std::vectorThreadData * datas;//1、创建一批线程for(int i 0; inum; i){std::string name thread- std::to_string(i1);ThreadData* td new ThreadData(g_tickets, name, mutex);threads.emplace_back(route, td, name);datas.emplace_back(td);}// 2. 启动 一批线程for (auto thread : threads){thread.Start();}// 3. 等待一批线程for (auto thread : threads){thread.Join();}sleep(1);// 4. 输出统计数据for (auto data : datas){std::cout data-_name : data-_total std::endl;delete data;}pthread_mutex_destroy(mutex);return 0;
}