добавить элемент в std::list в многопоточном режиме без мьютекса для С++

для текущего кода на выходе будет отображаться другой размер мл. Меня смущает то, что эта программа не падает, а несколько потоков пытаются изменить список в list_thread_safe. как std::list обрабатывает это в С++? спасибо во-первых.

(раскомментируйте код о мьютексе, он получит тот же размер мл.)

#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <map>
#include <unistd.h>
#include <list>
#include <mutex>
#include <algorithm>

std::mutex list_mutex; 
class list_thread_safe {
public:
    list_thread_safe() {
        std::cout<<"construct a list thread safe"<<std::endl;
    }

    ~list_thread_safe() {
        std::cout<<"destruct a list thread safe"<<std::endl;

    }

    void add_to_list(int new_v) {
        // std::lock_guard<std::mutex> guard(list_mutex);

        // add 10 elements to list 
        l.push_back(new_v);    
        l.push_back(new_v);  
        l.push_back(new_v);    
        l.push_back(new_v);     
        l.push_back(new_v);    
        l.push_back(new_v);  
        l.push_back(new_v);    
        l.push_back(new_v); 
        l.push_back(new_v);    
        l.push_back(new_v);  
    }
    std::list<int> l;

};

void add1_times(list_thread_safe& lts,int thread_num, int n) {
    for (int i=0; i< n ; i++) {
        lts.add_to_list(i);
    }
    std::cout<<"thread num "<<thread_num<<" done "<<std::endl;
    std::cout<<"thread list size: "<<lts.l.size()<<std::endl;

}
int main(){
    list_thread_safe ml;
    std::vector<std::thread> ths;
    int thread_num = 10;
    int add_num = 20;
    for(size_t i = 0; i < thread_num; i++)
    {
      printf("%d ", i);
      ths.push_back(std::thread(std::bind(add1_times, std::ref(ml), i, add_num)));
    }

    std::for_each(ths.begin(), ths.end(), std::mem_fn(&std::thread::join));
    std::cout<<"ml size:"<<ml.l.size()<<std::endl;

}

person THANK FLY    schedule 09.08.2018    source источник
comment
если у вас есть состояние гонки (два потока пишут в одну и ту же память), ваша программа имеет неопределенное поведение, std::list вообще не обрабатывает это   -  person 463035818_is_not_a_number    schedule 09.08.2018
comment
Таким образом, ваш код без мьютекса содержит неопределенное поведение. Бессмысленно спрашивать, почему неопределенное поведение имеет какой-то конкретный эффект.   -  person Daniel Langr    schedule 09.08.2018


Ответы (1)


"...как std::list обрабатывает это..."

std::list не является потокобезопасным. Безопасно читать std::list более чем в одном потоке. Но небезопасно иметь несколько потоков, изменяющих список, или один поток, изменяющий список и несколько читателей.

person Richard Critten    schedule 09.08.2018
comment
К вашему сведению, вы можете использовать >, чтобы добавить цитату - person Tas; 09.08.2018
comment
Безопасно читать std::list более чем в одном потоке. Это не полная история! Если вы добавляете данные из одного потока и пытаетесь читать из второго, то вам приходится делать синхронизацию с атомикой, мьютексом,... Компилятор не знал, что другой поток читает данные из первого потока! Это УБ! - person Klaus; 09.08.2018
comment
@Клаус, кажется, ты не прочитал остальную часть абзаца. - person Richard Critten; 09.08.2018
comment
Как я могу иметь список с несколькими читателями, который раньше не был записан с одного? Я не вижу ни одного случая использования, когда создается список (как минимум вызывался конструктор), а другой поток может читать данные без какой-либо синхронизации между ними. - person Klaus; 09.08.2018