概要
在并发编程中,线程安满是确保多个线程在同时访问共享资源时,不会引起数据竞争或意外的举动。在C++中,std::vector通常并不是线程安全的,因此在多线程环境中对std::vector举行读写操作大概会导致未界说举动。本文将通过实例验证std::vector的线程不安全性,并讨论如何解决这一题目。
整体架构流程
本文将分以下几部分讲解如何验证std::vector的线程不安全性:
1、多线程操作std::vector示例代码:构建一个简朴的C++代码示例,在多线程中对std::vector执行插入和读取操作。
2、题目分析:分析代码在运行时出现的线程题目,分析出现的原因
3、解决方法:介绍一下解决的方法。
技术名词表明
线程安全(Thread Safety):指在多线程步伐中,多个线程访问共享资源时,不会产生数据竞争或未界说举动。
数据竞争(Data Race):多个线程并发访问共享资源,并且至少一个线程执行写操作时,发生的竞争征象。
锁(Mutex):一种同步机制,用于防止多个线程同时访问共享资源。
技术细节
示例代码
以下代码展示了一个多线程环境中对std::vector举行读写操作的示例,验证其线程不安全性。
- #include <iostream>
- #include <pthread.h>
- #include <string>
- #include <vector>
- #include <unistd.h>
- using namespace std;
- class Thread
- {
- public:
- Thread(string &name) : _threadname(name) {}
- bool start()
- {
- sleep(1);//这里sleep是为了让现象变得固定,不加sleep,则现象就太随机,不容易画图分析
- int n = pthread_create(&_tid, nullptr, threadroutine, this);
- if (n == 0)
- {
- return true;
- }
- return false;
- }
- static void *threadroutine(void *args)
- {
-
- Thread *self = static_cast<Thread *>(args);
- cout << self->_threadname << endl;
- return nullptr;
- }
- void Join()
- {
- pthread_join(_tid, nullptr);
- }
- private:
- pthread_t _tid;
- std::string _threadname;
- };
- int main()
- {
- vector<Thread> threads;
- for (int i = 0; i < 10; i++)
- {
- string name = "thread-" + to_string(i);
- Thread thread(name);
- threads.push_back(thread);
- threads[i].start();
-
- }
- for (auto &thread : threads)
- {
- thread.Join();
- }
- return 0;
- }
复制代码 代码征象
可以发现,有些_threadname没有打印出来,有些打印出来了,因为加了sleep的原因,这个征象还是比较固定,容易分析的,那么原因出在哪了,没错,就是vector,vector的扩容题目。
分析代码
线程并发执行引发的vector扩容造成的线程安全题目
分析征象
来验证一下vector的扩容
只必要添加一行,std::cout<<threads.capacity()<<std::endl;
- for (int i = 0; i < 10; i++)
- {
- std::cout<<threads.capacity()<<std::endl;
- string name = "thread-" + to_string(i);
- Thread thread(name);
- threads.push_back(thread);
- threads[i].start();
-
- }
复制代码 征象
至此,验证STL容器的vector线程不安全完成。
解决方法
这里提2种解决办法
1、先把Thread放进vector,最后再遍历vector来启动
2、举行加锁,这里的加锁也要留心,加锁不正确,仍然会导致线程安全题目
- int main()
- {
- vector<Thread> threads;
- for (int i = 0; i < 10; i++)
- {
- string name = "thread-" + to_string(i);
- Thread thread(name);
- threads.push_back(thread);
- }
- for (int i = 0; i < 10; i++)
- {
- threads[i].start();
- }
- for (auto &thread : threads)
- {
- thread.Join();
- }
- return 0;
- }
复制代码 加锁的代码,注意加锁和释放锁的机遇,不正确的加锁仍然会有题目
- #include <iostream>
- #include <pthread.h>
- #include <string>
- #include <vector>
- #include <unistd.h>
- using namespace std;
- pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- class Thread
- {
- public:
- Thread(string &name) : _threadname(name) {}
- bool start()
- {
- pthread_mutex_lock(&lock);
- // sleep(1); // 这里sleep是为了让现象变得固定,不加sleep,则现象就太随机,不容易画图分析
- int n = pthread_create(&_tid, nullptr, threadroutine, this);
- if (n == 0)
- {
- return true;
- }
- return false;
- }
- static void *threadroutine(void *args)
- {
-
- Thread *self = static_cast<Thread *>(args);
- cout << self->_threadname << endl;
- pthread_mutex_unlock(&lock);
- return nullptr;
- }
- void Join()
- {
- pthread_join(_tid, nullptr);
- }
- private:
- pthread_t _tid;
- std::string _threadname;
- };
- int main()
- {
- vector<Thread> threads;
- for (int i = 0; i < 10; i++)
- {
-
- string name = "thread-" + to_string(i);
- Thread thread(name);
- pthread_mutex_lock(&lock);
- threads.push_back(thread);
- pthread_mutex_unlock(&lock);
- threads[i].start();
- }
- for (auto &thread : threads)
- {
- thread.Join();
- }
- return 0;
- }
复制代码 小结
在多线程场景中,std::vector 并发访问和扩容会导致数据竞争、无效指针、内存泄漏等题目。通过该案例分析,能够能加深刻的熟悉到线程安全带来的危害,实验的是string,那如果是金钱呢,线程安全题目不可忽视
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |