1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #include <gtest/gtest.h> 16 #include <thread> 17 #include <string> 18 19 #include "rwlock.h" 20 21 using namespace testing::ext; 22 using namespace std; 23 24 namespace OHOS { 25 namespace { 26 27 class UtilsRWLockTest : public testing::Test {}; 28 29 // This class is designed for test RWLock. "buf" is protected by "rwLock". 30 class TestRWLock { 31 public: TestRWLock()32 TestRWLock():rwLock(), buf() {} 33 TestRWLock(bool writeFirst)34 explicit TestRWLock(bool writeFirst):rwLock(writeFirst), buf() {} 35 WriteStr(const string & str)36 void WriteStr(const string& str) 37 { 38 rwLock.LockWrite(); 39 for (auto it = str.begin(); it != str.end(); it++) { 40 buf.push_back(*it); 41 this_thread::sleep_for(std::chrono::milliseconds(10)); // 10: Extend time of holding the lock 42 } 43 rwLock.UnLockWrite(); 44 return; 45 } 46 ReadStr(string & str)47 void ReadStr(string& str) 48 { 49 rwLock.LockRead(); 50 for (auto it = buf.begin(); it != buf.end(); it++) { 51 str.push_back(*it); 52 this_thread::sleep_for(std::chrono::milliseconds(10)); // 10: Extend time of holding the lock 53 } 54 rwLock.UnLockRead(); 55 return; 56 } 57 private: 58 Utils::RWLock rwLock; 59 string buf; 60 }; 61 62 const string WRITE_IN_1("write1"); 63 const string WRITE_IN_2("write2"); 64 65 /* 66 * @tc.name: testRWLock001 67 * @tc.desc: RWLock here is under write-first mode. If there are some writing operation waiting, 68 * reading will never happen. Reading operations are likely to run at the same time, when all writing operations 69 * have finished. 70 */ 71 HWTEST_F(UtilsRWLockTest, testRWLock001, TestSize.Level1) 72 { 73 TestRWLock test; 74 75 thread first(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_1))); 76 this_thread::sleep_for(std::chrono::milliseconds(4)); // Try our best to make `first` get the lock 77 78 string readOut1(""); 79 thread second(bind(&TestRWLock::ReadStr, ref(test), ref(readOut1))); 80 thread third(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_2))); 81 string readOut2(""); 82 thread fourth(bind(&TestRWLock::ReadStr, ref(test), ref(readOut2))); 83 84 85 first.join(); 86 second.join(); 87 third.join(); 88 fourth.join(); 89 90 EXPECT_EQ(readOut1, WRITE_IN_1 + WRITE_IN_2); 91 EXPECT_EQ(readOut2, WRITE_IN_1 + WRITE_IN_2); 92 } 93 94 /* 95 * @tc.name: testRWLock002 96 * @tc.desc: RWLock here is not under write-first mode. So if there are writing and reading operations in queue 97 * with a writing mission running, they will compete when the writing mission completing, but reading operations are 98 * likely to run at the same time. 99 */ 100 HWTEST_F(UtilsRWLockTest, testRWLock002, TestSize.Level1) 101 { 102 TestRWLock test(false); 103 104 thread first(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_1))); 105 this_thread::sleep_for(chrono::milliseconds(4)); 106 107 string readOut1(""); 108 thread second(bind(&TestRWLock::ReadStr, ref(test), ref(readOut1))); 109 thread third(bind(&TestRWLock::WriteStr, ref(test), ref(WRITE_IN_2))); 110 string readOut2(""); 111 thread fourth(bind(&TestRWLock::ReadStr, ref(test), ref(readOut2))); 112 113 first.join(); 114 second.join(); 115 third.join(); 116 fourth.join(); 117 118 EXPECT_EQ(readOut1, readOut2); 119 } 120 } // namespace 121 } // namespace OHOS