可能出现的线程安全问题
- 数据竞争:多个线程同时访问共享资源,由于没有同步机制,可能导致一个线程读取到正在被另一个线程修改的数据,从而得到不一致或错误的结果。例如,一个线程正在更新共享资源,而另一个线程同时读取这个资源,读取到的可能是部分更新的数据。
- 悬空引用:如果共享资源在某个线程中被释放,而其他线程仍然持有指向该资源的常量引用,那么这些引用就会变成悬空引用,访问悬空引用会导致未定义行为。
保证线程安全的分析与解决方案
- 使用互斥锁(Mutex)
- 分析:互斥锁可以保证在同一时间只有一个线程能够访问共享资源。当一个线程获取到互斥锁时,其他线程必须等待,直到该线程释放互斥锁。
- 代码示例(C++):
#include <iostream>
#include <mutex>
#include <thread>
class SharedResource {
public:
int data;
SharedResource(int value) : data(value) {}
};
std::mutex resourceMutex;
SharedResource* sharedResourcePtr = new SharedResource(0);
const SharedResource& getSharedResource() {
std::lock_guard<std::mutex> lock(resourceMutex);
return *sharedResourcePtr;
}
void threadFunction() {
const SharedResource& resource = getSharedResource();
std::cout << "Thread read data: " << resource.data << std::endl;
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i) {
threads[i] = std::thread(threadFunction);
}
for (auto& thread : threads) {
thread.join();
}
delete sharedResourcePtr;
return 0;
}
- 使用读写锁(Read - Write Lock)
- 分析:读写锁允许多个线程同时进行读操作,但只允许一个线程进行写操作。当有写操作时,所有读操作和其他写操作都必须等待。这样可以提高读操作的并发性能,同时保证写操作的原子性。
- 代码示例(C++,使用
std::shared_mutex
):
#include <iostream>
#include <shared_mutex>
#include <thread>
class SharedResource {
public:
int data;
SharedResource(int value) : data(value) {}
};
std::shared_mutex resourceMutex;
SharedResource* sharedResourcePtr = new SharedResource(0);
const SharedResource& getSharedResource() {
std::shared_lock<std::shared_mutex> lock(resourceMutex);
return *sharedResourcePtr;
}
void readThreadFunction() {
const SharedResource& resource = getSharedResource();
std::cout << "Read Thread read data: " << resource.data << std::endl;
}
void writeThreadFunction() {
std::unique_lock<std::shared_mutex> lock(resourceMutex);
sharedResourcePtr->data++;
std::cout << "Write Thread updated data" << std::endl;
}
int main() {
std::thread readThreads[10];
std::thread writeThread(writeThreadFunction);
for (int i = 0; i < 10; ++i) {
readThreads[i] = std::thread(readThreadFunction);
}
for (auto& thread : readThreads) {
thread.join();
}
writeThread.join();
delete sharedResourcePtr;
return 0;
}