zoukankan      html  css  js  c++  java
  • 操作系统 lab3 笔记

    操作系统 Lab3

    昨天和前天把MoreWindows的秒杀线程系列看了个大部分,今天去图书馆自己动手写了下读者写着问题,几乎写了一整天,太挫了。当然收获也很多。

    读者写者问题是很经典的进程/线程同步问题,在MoreWindows那里介绍的是一写者与多读者的情况,读者与写者的优先级一样。多个读者可以同时读取,读的时候写者不能写,写的时候读者不能读。Lab3这的要求多一些,情况复杂一些。是多读者多写者的情况,并且规定写者有较高优先级。因为太挫了,所以暂时只整了个同等优先级的情况。先记录着。我是用critical section来实现互斥,用event来实现同步。(有空再用mutexsemaphore实现一下)

    我从原先看的一写者的情况开始构思,想着能不能直接把写者数量加上去就可以跑了。发现不行,因为

    (1)等待的写者要等正在写的写者写完

    (2)等待的写者要等所有正在读的读者读完

    这两种同步逻辑上就是不一样的,用一个event容易出问题。

    关于互斥没多想,只想着reader数目增加和自定义输出的时候要开个关键域包着,没想到漏了一个(后面说)。

    本来打算把自定义输出的关键域放在封装好的输出函数里的,后来发现不行,因为输出不但要设置颜色,输出完还要变回来,所以要用关键域把整个输出的语句块给包住,也就是:

    1 EnterCriticalSection( &csConsoleColor );
    2 SetConsoleColor( FOREGROUND_GREEN | FOREGROUND_RED );
    3 int countOfOutput = vfprintf( stdout, format, pArgList);
    4 SetConsoleColor( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
    5 LeaveCriticalSection( &csConsoleColor );

    这样就可以保证输出完在变颜色了(我读者是白色,写者是黄色)

    貌似还出现过一个问题,就是:

    for ( ; writec<WRITER_NUMBER; writec++ )
    {
        writer[writec] = ( HANDLE )_beginthreadex( NULL, 0, WriterThread, NULL, 0, NULL );
        Sleep( rand()%100 );
    }

    这的WRITER_NUMBER当时从上面copy过来的时候忘了改了(原来是2)。巨坑爹因为这个小错,程序跑出了很奇葩的结果,写者正在写者,程序就结束了。应该是写者被重新初始化的原因。这里提醒自己:一旦碰到无法解释的奇葩错误,先检查下自己的代码里有没有变量名函数名写错、copy完忘了改特定部分的错误。当时一度以为WaitForMultipleObjects这个函数的使用出了问题。后来验证过,没有。这个函数就是等待指定handle上的所有内核变量变成触发态,就是signaled.

    另一个改动是h_e_reader = CreateEvent( NULL, TRUE, TRUE, NULL ); 把第二个参数改成TRUE了,意思是手动设置。就是在WaitForSingleObject( h_e_reader, INFINITE ); 之后不会自动调用ResetEvent( h_e_reader )。逻辑上我认为也不需要,写者开始写的时候,读者依然是没有在读的,所以自然不应该自动重置。

    改到现在,发现在运行几个读写者之后,会出现:

    1023号读者正在读取

    2420号写者正在写入

    2223号读者正在读取

    3215号读者正在读取

    这种问题,是逻辑出了问题,仔细检查后,发现了问题。

    问题在于写者的WaitForSingleObject( h_e_reader, INFINITE );

    和读者的WaitForSingleObject( h_e_writer, INFINITE );

    假设读者线程在跑完WaitForSingleObject( h_e_writer, INFINITE ); 后,操作系统立即切换到写者线程,然后写者跑WaitForSingleObject( h_e_reader, INFINITE ); 这样,就会出现同时读写的问题。解决方法很简单,就是把读写者的WaitForSingleObject一直到下面ResetEvent和输出一起用一个关键域包住。这样就不会出现同时读写的情况。至此问题得到解决。

    还是自己打代码来的印象深刻,和copy完再改是完全不一样的。

    代码:

      1 #include <stdio.h>
      2 #include <stdarg.h>
      3 #include <Windows.h>
      4 #include <process.h>
      5 
      6 
      7 int ReaderPrintf( char* format, ... );
      8 int WriterPrintf( char* format, ... );
      9 bool SetConsoleColor( WORD outAttributes );
     10 unsigned int __stdcall ReaderThread( PVOID p );
     11 unsigned int __stdcall WriterThread( PVOID p );
     12 
     13 
     14 //关键段和event的声明
     15 CRITICAL_SECTION csConsoleColor, csReaderCount, csReadWrite;
     16 HANDLE h_e_reader, h_e_writer, h_e_writerwriter;
     17 
     18 //有多少个正着读的读者
     19 int readerCount;
     20 
     21 //读写者数目
     22 const int READER_NUMBER = 20;
     23 const int WRITER_NUMBER = 12;
     24 
     25 void main()
     26 {
     27     //for循环里的递增量
     28     int readc, writec;
     29 
     30     readerCount = 0;
     31 
     32     //关键段和event的初始化
     33     InitializeCriticalSection( &csConsoleColor );
     34     InitializeCriticalSection( &csReaderCount );
     35     InitializeCriticalSection( &csReadWrite );
     36     h_e_reader = CreateEvent( NULL, TRUE, TRUE, NULL );
     37     h_e_writer = CreateEvent( NULL, TRUE, TRUE, NULL );
     38     h_e_writerwriter = CreateEvent( NULL, FALSE, TRUE, NULL );
     39 
     40     //读写者的handle
     41     HANDLE reader[READER_NUMBER];
     42     HANDLE writer[WRITER_NUMBER];
     43 
     44     //先初始化10个读者
     45     for( readc = 0; readc<10; readc++ )
     46     {
     47         reader[readc] = ( HANDLE )_beginthreadex( NULL, 0, ReaderThread, NULL, 0, NULL );        
     48         Sleep( rand()%100 );
     49     }
     50     
     51     //初始化6个写者
     52     for ( writec = 0; writec<6; writec++ )
     53     {
     54         writer[writec] = ( HANDLE )_beginthreadex( NULL, 0, WriterThread, NULL, 0, NULL );
     55         //Sleep( rand()%100 );
     56     }
     57     
     58     //Sleep( 50 );
     59 
     60     //初始化剩下的读者
     61     for( ; readc<READER_NUMBER; readc++ )
     62     {
     63         reader[readc] = ( HANDLE )_beginthreadex( NULL, 0, ReaderThread, NULL, 0, NULL );
     64         Sleep( rand()%50 );
     65     }
     66 
     67     //初始化剩下的写者
     68     for ( ; writec<WRITER_NUMBER; writec++ )
     69     {
     70         writer[writec] = ( HANDLE )_beginthreadex( NULL, 0, WriterThread, NULL, 0, NULL );
     71         Sleep( rand()%100 );
     72     }
     73         
     74     //等待所有内核变量的signal
     75     WaitForMultipleObjects( READER_NUMBER, reader, TRUE, INFINITE );
     76     WaitForMultipleObjects( WRITER_NUMBER, writer, TRUE, INFINITE );
     77 
     78 
     79     //printf("Already here! \n");
     80 
     81     //回收
     82     DeleteCriticalSection( &csConsoleColor );
     83     DeleteCriticalSection( &csReaderCount );
     84     DeleteCriticalSection( &csReadWrite );
     85     for( int i = 0; i<READER_NUMBER; i++ )
     86         CloseHandle( reader[i] );
     87     for( int i = 0; i<WRITER_NUMBER; i++)
     88         CloseHandle( writer[i] );
     89 
     90 }
     91 
     92 //实现读者输出,字体颜色:白
     93 int ReaderPrintf( char* format, ... )
     94 {
     95     va_list pArgList;
     96 
     97     va_start( pArgList, format );
     98     EnterCriticalSection( &csConsoleColor );
     99     int countOfOutput = vfprintf( stdout, format, pArgList );    
    100     LeaveCriticalSection( &csConsoleColor );
    101     va_end( pArgList );
    102 
    103     return countOfOutput;
    104 }
    105 
    106 //实现写者输出,字体颜色:黄
    107 int WriterPrintf( char* format, ... )
    108 {
    109     va_list pArgList;
    110 
    111     va_start( pArgList, format );
    112     EnterCriticalSection( &csConsoleColor );
    113     SetConsoleColor( FOREGROUND_GREEN | FOREGROUND_RED );
    114     int countOfOutput = vfprintf( stdout, format, pArgList);
    115     SetConsoleColor( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
    116     LeaveCriticalSection( &csConsoleColor );
    117     va_end( pArgList );
    118 
    119     return countOfOutput;
    120 }
    121 
    122 
    123 //封装控制台字体颜色控制的函数
    124 bool SetConsoleColor( WORD outAttributes )
    125 {
    126     HANDLE console = GetStdHandle( STD_OUTPUT_HANDLE );
    127     if( console == INVALID_HANDLE_VALUE )
    128         return false;
    129     
    130     SetConsoleTextAttribute( console, outAttributes );    
    131 
    132     return true;
    133 }
    134 
    135 //读者线程
    136 unsigned int __stdcall ReaderThread( PVOID p )
    137 {
    138     ReaderPrintf( "%d号读者正在等待读取\n", GetCurrentThreadId() );
    139 
    140     EnterCriticalSection( &csReadWrite );
    141     WaitForSingleObject( h_e_writer, INFINITE );
    142 
    143     EnterCriticalSection( &csReaderCount );
    144     readerCount++;
    145     if( readerCount > 0 )
    146         ResetEvent( h_e_reader );
    147     LeaveCriticalSection( &csReaderCount );
    148 
    149     ReaderPrintf( "%d号读者正在进行读取\n", GetCurrentThreadId() );
    150     LeaveCriticalSection( &csReadWrite );
    151     
    152 
    153     Sleep( rand()%100 );
    154 
    155     ReaderPrintf( "%d号读者读取完毕\n", GetCurrentThreadId() );
    156 
    157     EnterCriticalSection( &csReaderCount );
    158     readerCount--;
    159     if( readerCount == 0 )
    160         SetEvent( h_e_reader );
    161     LeaveCriticalSection( &csReaderCount );
    162     
    163     return 0;
    164 }
    165 
    166 //写者线程
    167 unsigned int __stdcall WriterThread( PVOID p )
    168 {
    169     WriterPrintf( "%d号写者正在等待写入\n", GetCurrentThreadId() );
    170 
    171     EnterCriticalSection( &csReadWrite );
    172     WaitForSingleObject( h_e_reader, INFINITE );
    173     WaitForSingleObject( h_e_writerwriter, INFINITE );
    174 
    175     ResetEvent( h_e_writer );
    176     
    177     WriterPrintf( "%d号写者正在进行写入\n", GetCurrentThreadId() );
    178     LeaveCriticalSection( &csReadWrite );
    179 
    180     
    181     Sleep( rand()%100 );
    182     
    183 
    184     WriterPrintf( "%d号写者写入完毕\n", GetCurrentThreadId() );
    185     SetEvent( h_e_writer );
    186     SetEvent( h_e_writerwriter );
    187     
    188     return 0;
    189 }
  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/HenryThinker/p/2818858.html
Copyright © 2011-2022 走看看