当前位置: 首页 > news >正文

多站点wordpress简数采集器福田庆三下巴

多站点wordpress简数采集器,福田庆三下巴,设计方案评审,科技让生活更美好500字六年级目录 类的线程安全 实现线程安全 构造函数在多线程中的安全性 析构函数多线程环境的安全 智能指针实现多线程安全 shared_ptr 非完全线程安全 shared_ptr可能导致对象生命周期延长 const引用可以减少传递shared_ptr开销 shared_ptr 智能指针块模块的优点 析构所在线程…目录 类的线程安全 实现线程安全  构造函数在多线程中的安全性 析构函数多线程环境的安全 智能指针实现多线程安全 shared_ptr 非完全线程安全 shared_ptr可能导致对象生命周期延长 const引用可以减少传递shared_ptr开销 shared_ptr 智能指针块模块的优点 析构所在线程问题分析 RAII的使用 enable_shared_from_this 使用场景分析 问题分析 enable_shared_from_this确保对象安全 weak_ptr 和 shared_ptr 结合 Bind的弱回调机制重点解决方案 弱回调机制的实现 类的线程安全 什么是class线程安全 多线程可以同时访问类的实例线程安全的类允许多个线程同时读取或者修改类的状态而不会引发数据不一致的问题线程之间交互会不会影响类的正确行为并发环境下线程的执行顺序不可控操作系统可能会在任意时刻调用线程在该环境下很容易导致其他异常行为。如果一个类的线程是安全的那么即使多线程交互也不会出现数据竞争和资源争夺问题无需额外的同步操作如果一个类是线程的安全的那么当调用这个类的时候就不需要使用锁、互斥量或者其他同步机制来确保其安全例如std::string std::vector std::map等类都是线程不安全的因为调用它们的时候需要使用锁机制 线程不安全会导致的问题 数据竞争多个线程同时修改同一块内存区域这样会导致数据不一致的情况崩溃或者未定义的行为在修改数据的时候会导致该种情况的发生  实现线程安全  构造函数在多线程中的安全性 构造函数在多线程环境下安全性 不要在构造函数中注册任何回调函数 构造函数执行的时候对象还没有初始化完成如果在构造函数中注册了回调函数此时可能会被其他线程调用这样就会导致该线程访问到了一个没有初始化完成的对象从而会导致未定义行为或数据不一致的问题不可以在构造函数中传递this指针给其他线程 同上对象还没有初始化完成就将自己的this指针给其他线程使用是一种很不安全的行为一定要确保构造函数完成后对象已经创建再将对象交给其他线程操作 解决方案 延迟泄漏this将this指针的传递放在对象构建之后。在对象创建之后可以通过初始化函数或者工厂模式将this指针传递给其他对象或者线程从而确保构造函数执行完毕后对象才会被外界访问使用工厂函数通过工厂函数来创建对象在对象初始化完成后在返回给调用者这样就不用直接在构造函数中暴露了 错误事例参考  #include iostreamclass Observable;class Observer { public:virtual void update() 0; // 纯虚函数用于接收更新通知 };class Foo : public Observer { public:// 错误在构造函数中直接注册 this会造成线程不安全Foo(Observable* s) {s-registerObserver(this); // 将 this 立即注册到 Observablestd::cout Foo 对象已构造并注册\n;}virtual void update() override {std::cout Foo 收到了更新通知\n;}private:int someData 0; // 假设这是一个重要的初始化数据 };class Observable { public:void registerObserver(Observer* o) {observer_ o;std::cout 观察者已注册\n;}void notifyObservers() {if (observer_) {observer_-update();}}private:Observer* observer_ nullptr; };int main() {Observable observable;Foo* foo new Foo(observable); // 在构造函数中注册 thisobservable.notifyObservers(); // 通知观察者可能在对象未完全初始化时访问delete foo;return 0; } 正确事例实现 延迟注册事例中通过独立的observer()方法将this注册到observable确保注册发色会给你在对象构造完成后避免未完全初始化的对象被访问 #include iostreamclass Observable;class Observer { public:virtual void update() 0; // 纯虚函数用于接收更新通知 };class Foo : public Observer { public:Foo() {// 在构造函数中仅初始化对象不进行任何注册操作std::cout Foo 对象已构造\n;}// 观察者更新接口实现virtual void update() override {std::cout Foo 收到了更新通知\n;}// 提供一个专门的函数用于在构造后进行注册void observe(Observable* s);private:// 内部成员变量int someData 0; };class Observable { public:void registerObserver(Observer* o) {observer_ o;std::cout 观察者已注册\n;}void notifyObservers() {if (observer_) {observer_-update();}}private:Observer* observer_ nullptr; };// Foo类的observe方法实现确保注册操作在构造完成后进行 void Foo::observe(Observable* s) {s-registerObserver(this); // 仅在对象构造后再注册 }int main() {Observable observable;Foo* foo new Foo(); // 构造对象foo-observe(observable); // 构造完成后进行注册observable.notifyObservers(); // 通知观察者进行更新delete foo;return 0; }析构函数多线程环境的安全 多线程环境下的析构比单线程析构是更为复杂的主要原因是因为其涉及到资源的竞争条件。如果在多线程环境下确保线程安全析构函数必须小心处理对象的状态同时与其他线程保持同步。 多线程环境下如何实现线程安全 避免多个线程同时读取或者写入共享状态每个线程对共享资源的访问顺序应该是按照某种顺序执行不可以让他们同时操作成员函数的操作相互独立函数的边界不应该发生重叠也就是多个线程不应该同时访问同一块资源每个成员函数的执行应该与其他函数隔离开避免相互干扰 借助mutex无法解决问题事例 首先两个线程存在线程竞争线程A在delete x之后便将x设置成为的NULL但是线程B在if(x)中检查了x但是由于两个线程之间都没有同步线程A销毁后线程B仍然可能在销毁后访问的x这样访问已经销毁对象肯定会导致对应的错误使用mutex无法解决问题原因分析因为Mutex只可以保证函数内的互斥访问但是不能控制线程之间的执行顺序也就是说销毁与执行的顺序是无法通过mutex来控制的  #include iostream #include thread #include mutexclass Foo { public:~Foo() {std::lock_guardstd::mutex lock(mutex_); // 互斥锁保护析构函数std::cout Foo 被销毁\n;}void update() {std::lock_guardstd::mutex lock(mutex_); // 互斥锁保护更新函数std::cout Foo 更新\n;}private:std::mutex mutex_; };Foo* x nullptr; // 全局对象指针多个线程共享void threadA() {delete x; // 线程A销毁对象x nullptr; // 设置 x 为 NULL }void threadB() {if (x) { // 线程B检查 x 是否为NULLx-update(); // 如果 x 不为NULL则调用 update()} else {std::cout x 是空指针\n;} }int main() {x new Foo(); // 初始化全局对象指针std::thread t1(threadA); // 线程A销毁对象std::thread t2(threadB); // 线程B调用 update()t1.join();t2.join();return 0; }​​​​​ mutex不仅不可以保证对象析构的线程安全还有可能导致死锁问题 mutex作为类成员具有局限性 mutex可以保护对象中其他数据成员的读写但是不能保护对象析构过程由于mutex的生命周期与对象是关联的也就是说对象如果销毁了那么mutex也会被销毁所以无法去为析构的时候提供保护死锁 多个线程对多个对象进行操作的时候如果锁的顺序不一致这样就会导致死锁例如线程A锁定对象a线程B锁定对象b双方互相等待对象释放锁的情况下就会导致死锁 智能指针实现多线程安全 shared_ptr / weak_ptr联合使用保证其线程安全 引用计数的线程安全因为两个指针都是采用原子操作的方式来维护引用计数的因此可以保证多个线程同时增加或者的减少引用计数时的线程安全访问控制利用weak_ptr检查对象是否仍然存在如果存在则将其提升为shared_ptr进行访问从而确保对象在销毁前的安全访问 事例代码 通过shared_ptr 实现自动管理对象的生命周期确保多线程对同一个对象的安全访问使用weak_ptr避免延长对象的生命周期与此同时使用lock()来提供安全的对象访问机制防止访问到已经销毁的对象   #include iostream #include memory #include threadstd::shared_ptrint globalPtr; // 全局 shared_ptrvoid threadFunc() {std::shared_ptrint localPtr globalPtr; // 安全地共享对象if (localPtr) {std::cout Thread accessing: *localPtr std::endl;} }int main() {globalPtr std::make_sharedint(42); // 初始化 shared_ptrstd::thread t1(threadFunc);std::thread t2(threadFunc);t1.join();t2.join();globalPtr.reset(); // 主线程释放对象其他线程仍然安全使用return 0; } shared_ptr 非完全线程安全 不能完全保证线程安全原因分析 引用计数线程安全因为其引用计数是通过原子操作来实现的也就是说多个线程可以安全的增减计数不会竞争同时只要还存在一个shared_ptr指向某个对象该对象的内存就不会被释放无法保证管理对象的线程安全多线程可以安全的访问同一个shared_ptr但是这些线程访问和修改对象的时候可能会导致数据不一致问题例如一个线程正在写入对象另一个线程也正在读取或者写入的时候此时就会产生数据竞争的情况读写冲突问题 同时读取此时通过计数是线程安全的同时写入除非对象在写的时候进行了加锁否则是线程不安全的读写冲突一个读一个写可能会导致最后数据不一致的问题 事例通过互斥锁来保证多线程访问对象的安全性  #include iostream #include memory #include thread #include mutexstd::shared_ptrint globalPtr; std::mutex mtx;void readSharedPtr() {std::lock_guardstd::mutex lock(mtx);if (globalPtr) {std::cout Reading: *globalPtr std::endl;} }void writeSharedPtr(int value) {std::lock_guardstd::mutex lock(mtx);if (globalPtr) {*globalPtr value;std::cout Writing: value std::endl;} }int main() {globalPtr std::make_sharedint(42);std::thread t1(readSharedPtr);std::thread t2(writeSharedPtr, 100);t1.join();t2.join();return 0; } shared_ptr可能导致对象生命周期延长 shared_ptr是引用计数的智能指针引用计数决定的对象的生命周期但是使用过程中如果有一个指向该对象的指针没有析构这样就会导致该对象永远不会被释放。 shared_ptr与回调函数 观察者设计模式中如果通过shared_ptr来管理管理者对象同时将这些对象放入vector容器中此时如果不能够正确管理这些观察者对象就可能会导致对象无法被释放也就是说如果没有手动的调用unregistyer()来将其从容器中移除shared_ptr这些对象就会始终存放在容器中引用计数是始终不会归零的这样一来对象的析构函数也就不会被调用从而引发内存泄漏 boost::bind与shared_ptr导致问题 利用bind进行回调的时候bind此时会持有一个shared_ptr的副本所以会使得对象的引用计数增加这也就意味着只要回调函数仍然存在该对象的引用计数也就永远不会归零对象的生命周期也就会被无限延长例如如果将一个shared_ptr绑定的一个函数中该指针的副本会一直存在直到该函数销毁为止  事例理解 将oberver1绑定到function中这样就导致了observer1的生命周期延长即使移除了它但还是不会立即销毁只有等到function销毁的时候observer1才会被销毁 #define BOOST_BIND_GLOBAL_PLACEHOLDERS #include iostream #include vector #include memory #include boost/bind.hpp #include boost/function.hppclass Observer { public:Observer(int id) : id_(id) {std::cout Observer id_ created. std::endl;}~Observer() {std::cout Observer id_ destroyed. std::endl;}void onNotify() {std::cout Observer id_ notified. std::endl;}private:int id_; };class Subject { public:void registerObserver(std::shared_ptrObserver obs) {observers_.push_back(obs); // 使用 shared_ptr 存储观察者}void unregisterObserver(std::shared_ptrObserver obs) {observers_.erase(std::remove(observers_.begin(), observers_.end(), obs), observers_.end());}void notifyAll() {for (auto obs : observers_) {if (obs) {obs-onNotify();}}}private:std::vectorstd::shared_ptrObserver observers_; };void delayedCallback(boost::functionvoid() func) {std::cout Callback will be called after delay... std::endl;func(); // 延迟回调调用 }int main() {Subject subject;// 创建两个观察者并注册std::shared_ptrObserver observer1(new Observer(1));std::shared_ptrObserver observer2(new Observer(2));subject.registerObserver(observer1);subject.registerObserver(observer2);// 这里的 boost::bind 使 shared_ptr 的引用计数增加boost::functionvoid() func boost::bind(Observer::onNotify, observer1);// 执行延迟回调delayedCallback(func);// 移除观察者subject.unregisterObserver(observer1);subject.unregisterObserver(observer2);// 通知所有观察者subject.notifyAll();// 注意observer1 的引用计数不会为 0因为 boost::function 持有了它的 shared_ptr 副本return 0; } const引用可以减少传递shared_ptr开销 const引用减少开销的原因 如果直接拷贝会增加引用计数也就是说shared_ptr的引用计数会增加使用const 引用的方式则不会增加计数这样就减少了锁的开销 void onMessage(const std::string msg) {std::shared_ptrFoo pFoo(new Foo(msg)); // 创建 shared_ptr持有 Foo 实例if (validate(pFoo)) { // 通过 const 引用传递 shared_ptrsave(pFoo); // 通过 const 引用传递 shared_ptr} } shared_ptr 智能指针块模块的优点 优点 减少析构函数调用次数因为使用shared_ptr可以自动管理对象的生命周期不需要用户调用析构函数所以就减少的开销shared_ptr可以指向任意类型的对象能够管理复杂对象的生命周期二进制兼容性即使对象大小改变旧的客户端代码依然可以兼容新版本的动态库 析构所在线程问题分析 在多线程环境下最后拥有对象的线程不一定是初始线程所以需要该处对最后析构线程进行分析。 析构线程不一定是初始化线程资源释放的时机是在shared_ptr离开作用域的时候发生也就是说在shared_ptr的析构函数会自动调用该对象的析构函数但是这个析构动作发生的线程不一定是创建该对象的线程因为对象的生命周期跨越了多个线程析构发生在最后持有shared_ptr的线程加入最后执行析构的是主线程那么后续行为的执行需要等待主线程执行完析构此时就会影响性能因为对一个对象的析构是一种十分耗时的行为主线程析构问题解决思路设计一些线程专门负责去析构对象实现的话可以通过一个队列将需要析构的对象都放入队列中这样就不会影响主线程执行 RAII的使用 涉及到资源管理必然不可以绕开RAIIRAII的核心思想就是在对象构建的时候同时获取资源并在对象销毁的时候同时释放资源。 避免手动释放资源程序中如何频繁的使用new那么就要频繁的使用delete去手动释放资源仅仅依靠自己手动释放资源是很容易出错的。所以要采用RAII通过自动化管理资源来减少这种错误例如在程序中多使用shared_ptr在其超出作用域时候自动释放其管理资源RAII管理共享资源shared_ptr通过应用计数来确保对象的生命周期确保没有任何shared_ptr持有对象的时候才释放资源。该种方式在多线程下十分适用多线程中使用shared_ptr来共享对象不需要手动管理对象的释放。避免循环引用在使用RAII管理资源的时候最重要的是需要避免循环引用的情况循环引用也就是会让引用计数永远不为零最终引发内存泄漏。在该情况下可以通过weak_ptr来打破循环引用因为weak_ptr是不会影响计数的其类似于一个不拥有对象的观察者通过weak_ptr.lock()提升为weak_ptr从而安全的访问对象 #include iostream #include memory #include thread #include chrono #include queue #include mutex #include condition_variable// 资源类构造时分配资源析构时释放资源 class Resource { public:Resource() {std::cout 资源已获取\n;}~Resource() {std::cout 资源已释放\n;} };// 模拟处理资源的函数 void processResource(std::shared_ptrResource res) {std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟处理延迟std::cout 正在处理资源\n; }// 阻塞队列类用于在线程间传递资源 template typename T class BlockingQueue { public:// 向队列中添加资源void push(T item) {std::lock_guardstd::mutex lock(mtx);queue.push(item);cond.notify_one(); // 唤醒等待的线程}// 从队列中取出资源T pop() {std::unique_lockstd::mutex lock(mtx);cond.wait(lock, [this]() { return !queue.empty(); }); // 等待直到队列非空T item queue.front();queue.pop();return item;}private:std::queueT queue;std::mutex mtx;std::condition_variable cond; };// 专用线程处理资源的析构 void workerThread(BlockingQueuestd::shared_ptrResource queue) {while (true) {auto res queue.pop(); // 从队列中获取资源processResource(res); // 处理资源// 资源会在这里自动析构} }int main() {// 创建阻塞队列和专用线程BlockingQueuestd::shared_ptrResource queue;std::thread worker(workerThread, std::ref(queue));// 主线程分配资源并将其传递给专用线程{auto res std::make_sharedResource(); // 使用shared_ptr分配资源queue.push(res); // 将资源传递给队列worker线程将接管资源}worker.join(); // 等待专用线程结束return 0; } enable_shared_from_this 使用场景分析 问题分析 当使用智能指针来管理对象的生命周期智能指针会自动管理对象资源的分配和释放从而避免内存泄漏。但是在某些情况下智能指针所管理的对象需要在其成员函数内存获取一个指向自身的shared_ptr。在这种情况下如果直接使用this指针操作可能会导致严重的生命周期管理的问题尤其在回调函数以及多线程环境下该问题会更明显结合下面的事例详细理解。 要点解释说明 Manner类通过继承enable_shared_this允许在Message类中获取自身shared_ptr指针同时通过deleteResource()方法模拟删除资源的操作Resource类该类持有一个指向Manner的指针在资源创建的时候就将销毁资源的函数绑定为析构时的回到函数。资源被销毁的时候这个回调函数会自动被调用生命周期管理通过shared_ptr 确保Manner的生命周期延长重点理解 也就是在Resource的析构函数中通过使用manager的shared_ptr调用Manner的deleteResource()方法从而保证在回调执行的时候Manner对象依然有效 调试内容源码 #include iostream #include memory #include functionalclass Manager : public std::enable_shared_from_thisManager { public:// 模拟删除资源的函数void deleteResource() {std::cout Manager: Deleting resource\n;}// 返回当前对象的shared_ptrstd::shared_ptrManager getSharedManager() {return shared_from_this();} };class Resource { public:Resource(std::shared_ptrManager mgr) : manager(mgr) {std::cout Resource Created\n;// 绑定析构时的回调函数调用Manager的deleteResource函数destructorCallback std::bind(Manager::deleteResource, manager);}~Resource() {std::cout Resource Destroyed\n;// 调用析构回调通知ManagerdestructorCallback();}private:std::shared_ptrManager manager;std::functionvoid() destructorCallback; };int main() {// 创建一个Manager对象并使用shared_ptr管理其生命周期std::shared_ptrManager manager std::make_sharedManager();{// 创建Resource对象并将Manager传递给它std::shared_ptrResource resource std::make_sharedResource(manager);} // Resource在此作用域结束时被销毁其析构函数被调用std::cout End of main\n;return 0; } enable_shared_from_this确保对象安全 解决上述问题则是通过C中提供的一个enable_shared_from_this机制来实现其是一个模版基类允许类的实例从其成员函数中安全的获取shared_ptr执行自身最终实现该对象的生命周期始终是由shared_ptr来控制的。 工作原理分析 继承enable_shared_from_this其是一个模版类提供了一个shared_from_this()方法允许类的成员函数获取一个指向该类对象的shared_ptr只要当该对象被shared_ptr管理的时候shared_from_this才是有效的确保生命周期延长重点当对象通过shared_ptr进行管理的时候调用shared_from_this可以确保即使所有其他地方持有shared_Ptr对象都被销毁当前对象也仍然有效。这也就是说成员函数或者回调函数使用该对象的时候程序可以确保该对象不会在使用的时候销毁. 注意其他地方的shared_ptr对象销毁的时候指针引用计数不会变成0的因为本对象中通过shared_from_this创建了一个新的shared_ptr所以该对象不会被销毁。 代码事例理解  #include iostream #include memoryclass Manager : public std::enable_shared_from_thisManager { public:Manager() {std::cout Manager Created\n;}~Manager() {std::cout Manager Destroyed\n;}// 返回自身的 shared_ptrstd::shared_ptrManager getSharedPtr() {return shared_from_this();}void performTask() {// 在成员函数内部获取 shared_ptrauto sharedManager shared_from_this();std::cout Performing task with shared_ptr\n;// 在这里 shared_ptr 的引用计数不会变成 0因为还有其他地方持有它} };int main() {// Step 1: 创建一个 shared_ptr 管理 Manager 对象std::shared_ptrManager manager1 std::make_sharedManager();std::cout Reference Count after creation: manager1.use_count() \n; // 引用计数为 1// Step 2: 调用成员函数获取 shared_ptrmanager1-performTask();std::cout Reference Count after performTask: manager1.use_count() \n; // 引用计数为 1因为没有新增外部持有者// Step 3: 在外部再获取一个 shared_ptrstd::shared_ptrManager manager2 manager1-getSharedPtr();std::cout Reference Count after getSharedPtr: manager1.use_count() \n; // 引用计数为 2// Step 4: 销毁 manager1manager1.reset(); std::cout Reference Count after resetting manager1: manager2.use_count() \n; // 引用计数为 1// Step 5: 销毁 manager2manager2.reset();std::cout All shared_ptrs destroyed\n;return 0; } weak_ptr 和 shared_ptr 结合 Bind的弱回调机制重点解决方案 弱回调机制的实现 实现机制分析 将shared_ptr绑定到bind和function中的时候其会延长绑定对象的生命周期也就是说只有绑定的function对象销毁的时候该指针才会销毁。通过该种方式保证了对象在回调的时候是安全但是相应的会导致对象生命周期会比预期的更长弱回调的核心思想避免对象的生命周期过度延长希望当对象存在的时候可以正常的执行回调函数如果对象销毁了则不再执行回调避免强引用带来的生命周期延长问题则是通过weak_ptr 具体实现 weak_ptr 不参与引用计数主要就是用来打破shared_ptr的循环引用问题当worker完成任务后通过weak_ptr::lock检查Manner是否还存在同时根据结果来决定是否通知Manner生命周期管理利用weak_ptr::lock检查Manner是否还存在如果对象被销毁则lock则返回空指针从而避免对已经销毁对象的访问 事例代码执行流程分析  Manner类 通过继承enable_shared_from_this让worker对象可以获取shared_ptrManner并在执行任务完成后通知后通知Manner #include iostream #include memory #include vector// 前置声明 Manager 类 class Manager;// Worker 类负责执行任务并在任务完成时通知 Manager class Worker { public:// 构造函数中传入 Manager 的 weak_ptrWorker(std::weak_ptrManager manager);~Worker();// 执行任务void doWork();private:// 使用 weak_ptr 避免循环引用std::weak_ptrManager manager_;// 通知 Manager 任务已完成void notifyManager(); };// Manager 类负责管理 Worker class Manager : public std::enable_shared_from_thisManager { public:Manager() {std::cout Manager Created\n;}~Manager() {std::cout Manager Destroyed\n;}// 注册 worker 完成任务的回调函数void registerWorker() {auto worker std::make_sharedWorker(shared_from_this());workers_.push_back(worker);worker-doWork();}void onTaskComplete() {std::cout Manager received task completion notification\n;}private:std::vectorstd::shared_ptrWorker workers_; };// 完整定义 Worker 类的方法 Worker::Worker(std::weak_ptrManager manager): manager_(manager) {std::cout Worker Created\n; }Worker::~Worker() {std::cout Worker Destroyed\n; }void Worker::doWork() {std::cout Worker is working...\n;// 模拟任务完成后通知 ManagernotifyManager(); }void Worker::notifyManager() {if (auto manager manager_.lock()) {// manager 有效时通知manager-onTaskComplete();} else {// 如果 Manager 已销毁通知失败std::cout Manager is no longer available\n;} }int main() {{// 创建一个 Manager 对象并用 shared_ptr 管理auto manager std::make_sharedManager();// 注册 Worker 并执行任务manager-registerWorker();std::cout Manager still exists\n;}// 当 Manager 销毁后Worker 再次尝试访问 Manager 将失败std::cout End of main\n;return 0; } 总结 weak_ptr 和 shared_ptr 与 bind相结合实现弱回调机制解决对象相互引用导致的生命周期问题weak_ptr弱化对象的引用如果对象还存在则执行回调如果对象不存在在不执行回调从而保证系统的稳定性和安全性
http://www.dnsts.com.cn/news/242669.html

相关文章:

  • 网站的备案在哪备案吗网站建设中效果
  • 深圳网站建设服务合同建设银行网站特色
  • 做单屏网站 高度是多少wordpress弹幕
  • 北京丰台网站优化wordpress应用商店主题
  • 申请关闭网站黄骅市市长
  • 网站 seo免费域名注册流程
  • 网站建设内容3000字wordpress如何设置头像
  • 建设装修公司网站谷歌seo搜索优化
  • 牟平做网站怎样用ps设计网站模板
  • 济南行知网网站建设北京中兴时代网站建设
  • 企业的网站内容管理系统设计专业哪个学校好
  • 南昌手机网站建设asp.net网站开发是什么
  • 系统网站设计订餐网站怎么做
  • 福田网站设计哪家好wordpress 折800模板
  • 个人资料展示网站哪种网站
  • 网站为什么没有被收录网站开发实训内容
  • 大沥网站开发公司官网网址
  • 网站建设及推广培训信息流推广渠道
  • 怎么修改网站图片深圳开发软件公司
  • wordpress娱乐网模板海口百度seo公司
  • 中美网站建设中国建筑装饰网设计师联盟
  • 中国建设信号工证网站wordpress 暖岛 主题
  • 微网站是手机网站吗wordpress vip付费插件
  • 网站修改图片怎么做如何查看网站外链
  • 做网站销售挣钱吗海口企业网站建设
  • 青海省公路建设服务网站天津做网站.都找津坤科技
  • 做旅游网站的原因长沙做网站团队
  • 淘客做网站有必要吗页面设计尺寸规范
  • 河南手机网站建设公司哪家好扫码点餐小程序怎么制作
  • 做app网站有哪些广州越秀公司网站建设