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 */
HWTEST_F(UtilsRWLockTest, testRWLock001, TestSize.Level1)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 */
HWTEST_F(UtilsRWLockTest, testRWLock002, TestSize.Level1)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