操作系统 多线程访问共享资源产生的问题

首先我们假设一种情况  创建了10个线程  这些线程都执行一个线程函数 (都做一个事)

如  我们设置了是个窗口 每个窗口都负责买火车票  我们的火车票的总数为100

卖完为止  

我们定义了一个全局变量

long ticket=100; 为票数

每卖出一张票  票数--

这里我们需要创建了10个线程  这些线程都执行一个线程函数 (买票)

但是 在多个线程同时访问一个共享资源时  会产生并发问题 

如:  多个线程同时卖同一张票

那么为了解决并发问题  我么的

解决方案:线程同步

线程同步方式:

1.原子访问:同一时间 只允许一个线程访问资源 volatile防止编译优化,对特殊地址的稳定访问.  直接对内存进行操作

这里想对票数--  可以用

InterlockedDecrement(&ticket);  他会对票数--  直接对内存进行操作

同时避免进程并行问题

CRITICAL_SECTION m_cs;

2.临界区(关键段)(用户模式下的线程同步 ):同一时刻只允许一个进程访问代码段

分为:

(1)直接阻塞:如果已经有线程在执行代码段  他就会等待  直到那个线程执行完代码后  锁会随机分配给一个等待的进程

主函数中:

//初始化关键段
    //InitializeCriticalSection(&m_cs);

线程函数中:

EnterCriticalSection(&m_cs);
if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            

            
            LeaveCriticalSection(&m_cs);
            
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

        锁的出口
        LeaveCriticalSection(&m_cs);

       

(2)旋转锁:如果已经有线程在执行代码段  他会等待一定的时间(由我们自己决定)  如果等待时间到了  代码段其他线程还是    没执行完  他就会走  不继续等待

这里不好测试  不直观  就不进行演示

(3)非阻塞:如果已经有线程在执行代码段 他就会走  不继续等待

主函数中:

//初始化关键段
    //InitializeCriticalSection(&m_cs);

线程函数中:

  while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


       

        if(!TryEnterCriticalSection(&m_cs))
            continue;//走开


        //EnterCriticalSection(&m_cs);

        

       
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            

            
            LeaveCriticalSection(&m_cs);
            
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

        
        LeaveCriticalSection(&m_cs);

       

    }
    return 0;

线程函数完整代码如下

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


        //原子访问
        //InterlockedDecrement(&ticket);//对共享资源执行--操作

        //锁的入口   只允许一个进程访问下列关键段

        //if(!TryEnterCriticalSection(&m_cs))//
            //continue;//走开


        //EnterCriticalSection(&m_cs);

        //事件的判断  看有没有信号  没信号就走
        if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))

        {
                continue;

        }



        //WaitForSingleObject(m_hMutex,INFINITE);
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            //SetEvent(m_hEvent);

            //ReleaseMutex(m_hMutex);
            //LeaveCriticalSection(&m_cs);
            ReleaseSemaphore(m_hSemaphore,1,NULL);
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

        //锁的出口
        //LeaveCriticalSection(&m_cs);

        //信号量
        ReleaseSemaphore(m_hSemaphore,1,NULL);

        //事件
        //SetEvent(m_hEvent);

        //互斥量
        //ReleaseMutex(m_hMutex);

    }
    return 0;

}

3.内核对象:同一时刻只允许一个线程访问代码段

(1)互斥量:一直等互斥量  直到等到为止  执行代码

//初始化互斥量
   //m_hMutex=CreateMutex(0,//安全属性
   //                     1,//初始拥有权
   //                     L"MyMutex"//名字
   //                     );
   //ReleaseMutex(m_hMutex);

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


        


        WaitForSingleObject(m_hMutex,INFINITE);
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            

            ReleaseMutex(m_hMutex);
           
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

       
        //互斥量
        ReleaseMutex(m_hMutex);

    }
    return 0;

}

(2)事件  分配事件信号 谁 抢到谁执行

//初始化事件
    //m_hEvent=CreateEventA(0,0,0,0);
    //SetEvent(m_hEvent);//初始信号为0  把信号设置为1  让线程去抢

 while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


        
        //事件的判断  看有没有信号  没信号就走
        if(WAIT_TIMEOUT==WaitForSingleObject(m_hEvent,10))

        {
                continue;

        }



        
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            SetEvent(m_hEvent);

            
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);


        //事件
        SetEvent(m_hEvent);

        
    }
    return 0;

(3)信号量:允许同一时间内指定数量的线程访问代码段

//初始化信号量
    m_hSemaphore=CreateSemaphoreW(0,//安全属性
                                 1,//初始化信号量总数
                                 10,//最大信号量总数
                                 0//名字
                                 );

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


       


       

        //信号的判断  看有没有信号  没信号就走
        if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))

        {
                continue;

        }



        
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            
            ReleaseSemaphore(m_hSemaphore,1,NULL);
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

      
        //信号量
        ReleaseSemaphore(m_hSemaphore,1,NULL);

        

    }
    return 0;

}

上述三种内核对象需要在最后句柄释放

if(m_hMutex)
    {
        CloseHandle(m_hMutex);
        m_hMutex=0;
    }
    if(m_hEvent)
    {
        CloseHandle(m_hEvent);
        m_hEvent=0;
    }
    if(m_hSemaphore)
    {
        CloseHandle(m_hSemaphore);
        m_hSemaphore=0;
    }

我们在这里实现了单例模式

//单例
    HANDLE hdl=OpenMutexW(MUTEX_ALL_ACCESS,0,L"MyMutex");
    if(hdl)
    {
        qDebug()<<"app is exists";
        exit(0);
    }

完整代码如下

#include <QCoreApplication>
#include <windows.h>
#include<QDebug>

long ticket=100;
CRITICAL_SECTION m_cs;// 临街
HANDLE m_hMutex;//互斥量
HANDLE m_hEvent;//事件
HANDLE m_hSemaphore;//信号量

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
    while(1)
        {
        if(ticket==0)
        {
            printf("Thread id[%d] go\n",GetCurrentThreadId());
            break;

        }

        Sleep(10);


        //原子访问
        //InterlockedDecrement(&ticket);//对共享资源执行--操作

        //锁的入口   只允许一个进程访问下列关键段

        //if(!TryEnterCriticalSection(&m_cs))//
            //continue;//走开


        //EnterCriticalSection(&m_cs);

        //事件的判断  看有没有信号  没信号就走
        if(WAIT_TIMEOUT==WaitForSingleObject(m_hSemaphore,10))

        {
                continue;

        }



        //WaitForSingleObject(m_hMutex,INFINITE);
        if(ticket==0)
        {
            printf("Thread id[%d] go-------\n",GetCurrentThreadId());


            //SetEvent(m_hEvent);

            //ReleaseMutex(m_hMutex);
            //LeaveCriticalSection(&m_cs);
            ReleaseSemaphore(m_hSemaphore,1,NULL);
            break;
        }
        ticket--;
        printf("Thread id[%d] ticket %d\n",GetCurrentThreadId(),ticket);

        //锁的出口
        //LeaveCriticalSection(&m_cs);

        //信号量
        ReleaseSemaphore(m_hSemaphore,1,NULL);

        //事件
        //SetEvent(m_hEvent);

        //互斥量
        //ReleaseMutex(m_hMutex);

    }
    return 0;

}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //单例
    HANDLE hdl=OpenMutexW(MUTEX_ALL_ACCESS,0,L"MyMutex");
    if(hdl)
    {
        qDebug()<<"app is exists";
        exit(0);
    }

    //初始化信号量
    m_hSemaphore=CreateSemaphoreW(0,//安全属性
                                 1,//初始化信号量总数
                                 10,//最大信号量总数
                                 0//名字
                                 );


    //初始化事件
    //m_hEvent=CreateEventA(0,0,0,0);
    //SetEvent(m_hEvent);//初始信号为0  把信号设置为1  让线程去抢


    //初始化关键段
    //InitializeCriticalSection(&m_cs);


    //初始化互斥量
   //m_hMutex=CreateMutex(0,//安全属性
   //                     1,//初始拥有权
   //                     L"MyMutex"//名字
   //                     );
   //ReleaseMutex(m_hMutex);


    HANDLE han=NULL;
    for(int  i=0;i<10;i++)
    {
          han=CreateThread(0,0,&ThreadProc,0,0,0);
          if(han)
          {
                  CloseHandle(han);
                  han=0;

          }
    }


    a.exec();
    //销毁关键段
    //DeleteCriticalSection(&m_cs);

    //释放内核对象  互斥量/事件
    if(m_hMutex)
    {
        CloseHandle(m_hMutex);
        m_hMutex=0;
    }
    if(m_hEvent)
    {
        CloseHandle(m_hEvent);
        m_hEvent=0;
    }
    if(m_hSemaphore)
    {
        CloseHandle(m_hSemaphore);
        m_hSemaphore=0;
    }
    return a.exec();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值