25_添加信号量

信号量机制

在多线程环境下,信号量机制的作用是协调各个线程,以确保它们能够正确、合理地使用公共资源。信号量是一种计数器,用于控制同时访问共享资源的线程数量。这里是信号量的一些主要作用:

  1. 并发控制:信号量维护一个许可集,限制了同时访问共享资源的线程数量。这有助于防止资源竞争和数据不一致的问题1
  2. 同步机制:线程在访问共享资源前必须获取信号量。如果信号量的值为零,表示没有可用资源,线程将等待直到其他线程释放资源2
  3. 资源管理:信号量可以作为一种资源计数器,管理有限的资源使用,如连接池、内存缓冲区等3
  4. 互斥锁:当信号量的初始值设置为1时,它可以作为互斥锁使用,确保每次只有一个线程可以访问资源1

信号量的操作通常包括两个主要动作:acquire()(获取)和release()(释放)。当线程完成资源的使用后,它会释放信号量,允许其他线程进入。这些操作都是原子的,确保了线程间的同步和资源的正确管理。

信号量和锁

信号量机制和锁是两种不同的同步机制,它们在多线程编程中用于不同的目的和场景。以下是它们之间的一些主要区别:

  1. 用途
  2. 计数
  3. 操作
  4. 所有权
  5. 类型

总的来说,锁更多地用于保证对共享资源的独占访问,而信号量提供了更高的灵活性,可以控制多个线程对共享资源的访问。在选择使用哪种同步机制时,需要根据具体的应用场景和需求来决定。

用信号量机制来控制并发线程的退出顺序

创建了一个简单的CELLSemaphore.cpp来负责OnRun的退出在close之前

//CELLSemaphore.cpp
#ifndef _CELL_SEMAPHORE_HPP_
#define _CELL_SEMAPHORE_HPP_

#include<chrono>
#include<thread>

//信号量
class CELLSemaphore
{
public:
    //阻塞当前线程
    void wait()
    {
        _isWaitExit = true;
        while(_isWaitExit)    //循环等待
        {
            std::chrono::milliseconds t(1);
            std::this_thread::sleep_for(t);
        }
    }
    //唤醒当前线程
    void wakeup()
    {
        _isWaitExit = false;
    }

private:
    bool _isWaitExit;
};

#endif // !_CELL_SEMAPHORE_HPP_

//虚假唤醒

在cellserver.cpp中的运用

private:
    CELLSemaphore _sem;
void Close()
    {
        printf("CellServer%d.Close begin\n", _id);
        if (_isRun)
        {
            _taskServer.Close();
            _isRun = false;
            _sem.wait();
        }
        printf("CellServer%d.Close end\n", _id);
    }

    void OnRun()
    {
        while (_isRun)
        {
            if (!_clientsBuff.empty())
            {
                std::lock_guard<std::mutex> lock(_mutex);
                for (auto pClient : _clientsBuff)
                {
                    _clients[pClient->sockfd()] = pClient;
                    pClient->serverId = _id;
                    if (_pNetEvent)
                        _pNetEvent->OnNetJoin(pClient);
                }
                _clientsBuff.clear();
                _clients_change = true;
            }

            if (_clients.empty())
            {
                std::chrono::milliseconds t(1);
                std::this_thread::sleep_for(t);
                _oldTime = CELLTime::getNowInMilliSec();
                continue;
            }

            fd_set fdRead;

            FD_ZERO(&fdRead);
            if (_clients_change)
            {
                _clients_change = false;
                _maxSock = _clients.begin()->second->sockfd();
                for (auto iter : _clients)
                {
                    FD_SET(iter.second->sockfd(), &fdRead);
                    if (_maxSock < iter.second->sockfd())
                    {
                        _maxSock = iter.second->sockfd();
                    }
                }
                memcpy(&_fdRead_bak, &fdRead, sizeof(fd_set));
            }
            else {
                memcpy(&fdRead, &_fdRead_bak, sizeof(fd_set));
            }

            timeval t{ 0,1 };
            int ret = select(_maxSock + 1, &fdRead, nullptr, nullptr, &t);
            if (ret < 0)
            {
                printf("selectÈÎÎñ½áÊø¡£\n");
                Close();
                return;
            }
            //else if (ret == 0)
            //{
            //  continue;
            //}
            ReadData(fdRead);
            CheckTime();
        }
        printf("CellServer%d.OnRun exit\n", _id);

        ClearClients();
        _sem.wakeup();
    }

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top