Template errors creating a map<int,std::thread> using map::emplace

I created a class to try out std::lock_guard.

The first function, UnsafeExample compiles and runs fine. The second example, SafeExample does not compile and a bunch of errors are thrown.

I have a hunch that it might have to do std::move(t) leaving t in an empty state but maybe not. Anyway, I want to have a mapping of int to threads (why not) instead of the usual vector.

1
2
3
4
5
6
7
8
9
10
11
struct SafeThreadCoutExample
{
    const int numThreads = -1;
    std::map<int, std::thread> threadHandles;
    std::mutex coutMutex;

    SafeThreadCoutExample(int nThreads) :  numThreads(nThreads) {}

    void UnsafeExample(void);
    void SafeExample(void);
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void SafeThreadCoutExample::UnsafeExample(void)
{
    // Create nThreads
    for (int i = 0; i < numThreads; i++)
    {
        threadHandles.emplace(std::make_pair(i, thread{ Task_PrintHelloWithIdAndExit, i }));
    }

    // Wait for all threads to finish
    for (int i = 0; i < numThreads; i++)
    {
        if (threadHandles[i].joinable())
        {
            threadHandles[i].join();
        }
        else
        {
            cout << "Thread-" << i << " NOT joinable!\n";
        }
    }
}


void SafeThreadCoutExample::SafeExample(void)
{
    // Create nThreads
    for (int i = 0; i < numThreads; i++)
    {
        thread t(Task_Safe_PrintHelloWithIdAndExit, i, coutMutex);
        threadHandles.emplace(std::make_pair(i, std::move(t)));
    }

    // Wait for all threads to finish
    for (int i = 0; i < numThreads; i++)
    {
        if (threadHandles[i].joinable())
        {
            threadHandles[i].join();
        }
        else
        {
            cout << "Thread-" << i << " NOT joinable!\n";
        }
    }
}


and the thread functions ...
1
2
3
4
5
6
7
8
9
10
void Task_PrintHelloWithIdAndExit(int id)
{
    cout << "Hello from thread id=" << id << "\n";
}

void Task_Safe_PrintHelloWithIdAndExit(int id, std::mutex &coutMutex)
{
    std::lock_guard<std::mutex> coutMutexGuard(coutMutex); // Upon creation, lock the mutex
    cout << "Hello from thread id=" << id << "\n";
}


and the compiler errors (it goes on ... to long to post)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1>ex_Threads.cpp
1>ManageThreads.cpp
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35): error C2661: 'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple': no overloaded function takes 3 arguments
1>(compiling source file 'ManageThreads.cpp')
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(516,5):
1>    could be 'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::pair<_First,_Second> &&)'
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35):
1>        'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::pair<_First,_Second> &&)': could not deduce template argument for 'std::pair<_First,_Second> &&' from 'std::mutex'
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(510,5):
1>    or       'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,const std::pair<_First,_Second> &)'
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35):
1>        'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,const std::pair<_First,_Second> &)': could not deduce template argument for 'const std::pair<_First,_Second> &' from 'std::mutex'
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(488,5):
1>    or       'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::tuple<_Types2...> &&)'
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35):
1>        'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::tuple<_Types2...> &&)': could not deduce template argument for 'std::tuple<_Types2...> &&' from 'std::mutex'
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(480,5):
1>    or       'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,const std::tuple<_Types2...> &)'
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35):
1>        'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,const std::tuple<_Types2...> &)': could not deduce template argument for 'const std::tuple<_Types2...> &' from 'std::mutex'
1>    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(463,5):
1>    or       'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex> &&)'
1>        C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\memory(3597,35):
1>        'std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex>::tuple(std::allocator_arg_t,const _Alloc &,std::tuple<void (__cdecl *)(int,std::mutex &),int,std::mutex> &&)': could not deduce template argument for '__formal'
1>            C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.42.34433\include\tuple(462,51):
1>            'std::enable_if_t<false,int>' : Failed to specialize alias template
Last edited on
I think the problem is that std::thread will copy the arguments by default but std::mutex is not copyable.

Try this instead:
 
thread t(Task_Safe_PrintHelloWithIdAndExit, i, std::ref(coutMutex));
Last edited on
Thanks Peter. That was it.

1. std::ref(coutMutex) was necessary, for the reason you stated.
2. "t" needs to be std::moved() into the pair, since it can't be copied.
3. Either std::map::emplace and std::map::insert() will work.

Simpler working example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <sstream>
#include <map>
#include <mutex>
#include <thread>

using std::cout;
using std::cin; 
using std::endl;
using std::ostringstream;
using std::map;
using std::pair;
using std::mutex; 
using std::lock_guard;
using std::thread;

void Task_PrintHelloAndSleep(int i, std::mutex &mu)
{
    lock_guard<mutex> coutGuard(mu); 
    cout << "[Thread-" << i << "] " << "Hello!\n";
}

struct RunMe
{
    int nThreads = -1; 
    map<int, thread> tmap; 

    RunMe(int nThreads) : nThreads(nThreads)
    {

    }

    // Notice the order in which threads cout isn't guaranteed - any thread can grab the mutex before other threads, even though the threads were created in order!
    void SafeCout(void)
    {
        for (int i = 0; i < nThreads; i++)
        {
            thread t(Task_PrintHelloAndSleep, i, std::ref(coutMtx));
            tmap.emplace(std::make_pair(i, std::move(t)));
        }

        for (int i = 0; i < nThreads; i++)
        {
            if (tmap[i].joinable())
            {
                tmap[i].join();
            }
        }

        tmap.clear(); // Cleanup so that SafeCout can be called again with new threads, same index.
    }

    mutex coutMtx; 
};

int main()
{
    RunMe rme(10); 

    const int nRuns = 100; // Run it a bunch of times to check that successes weren't a fluke
    for (int i = 0; i < nRuns; i++) { 
        cout << "[Run #" << i << "]\n";
        rme.SafeCout(); 
    }
    
    cout << "End of program.\n";
}
Last edited on
Registered users can post here. Sign in or register to post.