C++ multi-threading demo I recently started learning C++ and here's a simple program I wrote to demonstrate how multi-threading work. This program simply fetches JSON strings from a whether API for a list of cities read from a text file.
Can you guys take a look? And I really appreciate professionals' views.

#include &lt;iostream&gt;
#include &lt;ctime&gt;
#include &lt;typeinfo&gt;
#include &lt;thread&gt;
#include &lt;mutex&gt;
#include &lt;vector&gt;
#include &lt;fstream&gt;
#include &lt;string&gt;
#include &lt;curl/curl.h&gt;

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
void fetchJson(int);
void getCityList();
void fetch_weather_async();

const char *URL_BASE = "https://www.metaweather.com/api/location/search/?query=";
const char *CITY_LIST_FILE = "city_list.txt";
std::vector&lt;std::string&gt; cities;
int current_city = -1;
std::mutex city_counter_lock;
std::time_t start;
std::time_t finish;

int main(void){
    getCityList();
    std::cout &lt;&lt; "Read " &lt;&lt; cities.size() &lt;&lt; " cities from file..." &lt;&lt; std::endl;

    std::cout &lt;&lt; "Using 2 threads to fetch..." &lt;&lt; std::endl;
    std::thread thread_1(&amp;fetch_weather_async);
    std::thread thread_2(&amp;fetch_weather_async);

    start = std::time(nullptr);
    thread_1.join();
    thread_2.join();
    finish = std::time(nullptr);

    std::cout &lt;&lt; "Duration " &lt;&lt; (finish - start) &lt;&lt; "s" &lt;&lt; std::endl;

    return 0;
}

void fetch_weather_async(){
    while (current_city + 1 &lt; (int) cities.size()){
        city_counter_lock.lock();
        int city_index = 0;
        if (current_city + 1 &lt; (int) cities.size()) {
            city_index = ++current_city;
        }
        city_counter_lock.unlock();

        std::cout &lt;&lt; "requesting " &lt;&lt; city_index &lt;&lt; std::endl;  
        fetchJson(city_index);
        std::cout &lt;&lt; "acquired " &lt;&lt; city_index &lt;&lt; std::endl;    
    }
}

void getCityList(){
    std::ifstream idFile(CITY_LIST_FILE);
    std::string currentLine;

    if(idFile.is_open()){
        while(! idFile.eof()){
            getline (idFile, currentLine);
            cities.push_back(currentLine);  
        }
    }
    idFile.close();
}

void fetchJson(int i){    
    CURL *curl;
    CURLcode res;
    std::string readBuffer;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, (URL_BASE + cities[i]).c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &amp;readBuffer);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);

        std::cout &lt;&lt; i &lt;&lt; " : " &lt;&lt; readBuffer &lt;&lt; std::endl;
    }
}

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
    ((std::string*)userp)-&gt;append((char*)contents, size * nmemb);
    return size * nmemb;
}


The city list file (city_list.txt) contains:

Adelaide
Amsterdam
Ankara
Athens
Atlanta
Auckland
Baghdad
Bangkok
Beijing
Belfast
Berlin
Blackpool
Bridgeport
Brussels
Bucharest
Budapest
Busan
Cairo
Caracas
Cardiff
Casablanca
Charlotte
Copenhagen
Dallas
Damascus
Dhaka
Dublin
Edinburgh
Glasgow
Helsinki
Jakarta
Kiev
Kinshasa
Lagos
Lahore
Lima
Lisbon
London
Madrid
Manila
Milan
Minsk
Moscow
Nairobi
Newark
Newcastle
Oakland
Oslo
Paris
Philadelphia
Plymouth
Portland
Portsmouth
Prague
Pyongyang
Riyadh
Rome
Santander
Santiago
Santorini
Seoul
Singapore
Sofia
Stockholm
Sunderland
Taipei
Tokyo
Vienna
Warsaw
Wellington
Windhoek
Zagreb
Prefer using a lock guard: 

int city_index = 0;
{
    std::lock_guard&lt;std::mutex&gt; guard(city_counter_lock);
    if (current_city + 1 &lt; (int) cities.size()) {
        city_index = ++current_city;
    }
}


This makes sure that an exception will not leave the mutex locked;



You will need to handle failures to get the webpage. If res != CURLE_OK then a failure occurred somewhere.



You are encouraged to reuse the CURL handle you can do so by creating it inside fetch_weather_async before the loop and passing it into fetchJson

void fetch_weather_async(){
    CURL *curl;

    curl = curl_easy_init();

    if(!curl) return;
    while (current_city + 1 &lt; (int) cities.size()){
        int city_index = 0;
        {
            std::lock_guard&lt;std::mutex&gt; guard(city_counter_lock);
            if (current_city + 1 &lt; (int) cities.size()) {
                city_index = ++current_city;
            }
        }

        std::cout &lt;&lt; "requesting " &lt;&lt; city_index &lt;&lt; std::endl;  
        fetchJson(city_index, curl);
        std::cout &lt;&lt; "acquired " &lt;&lt; city_index &lt;&lt; std::endl;    
    }
    curl_easy_cleanup(curl);
}

void fetchJson(int i, CURL *curl){    
    CURLcode res;
    std::string readBuffer;


    curl_easy_setopt(curl, CURLOPT_URL, (URL_BASE + cities[i]).c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &amp;readBuffer);
    res = curl_easy_perform(curl);
    if(res == CURLE_OK)
        std::cout &lt;&lt; i &lt;&lt; " : " &lt;&lt; readBuffer &lt;&lt; std::endl;

}