C++-并发与多线程

简介

thread

C++11 引入了 std::thread 库以实现多线程

成员函数

  1. thread(funcName) - 构造函数,实例化线程
  2. join() - 调用该函数会阻塞当前线程,及让主线程等待子线程。需要注意的是线程对象执行了join后joinable就为false了,所以只能调用join一次。
  3. thread::detach() - 将当前线程对象所代表的执行实例与该线程对象分离,使得线程的执行可以单独进行。一旦线程执行完毕,它所分配的资源将会被释放
  4. get_id(),获取线程ID,返回一个类型为std::thread::id的对象
  5. joinable(),检查线程是否可被join
  6. native_handle,该函数返回与std::thread具体实现相关的线程句柄

锁(mutex)

mutex是用来保证线程同步的,防止不同的线程同时操作同一个共享数据。

但是使用mutex是不安全的,当一个线程在解锁之前异常退出了,那么其它被阻塞的线程就无法继续下去

成员函数

  1. lock() - 调用线程将锁住该互斥量
  2. unlock() - 解锁,释放对互斥量的所有权
  3. try_lock() - 尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int cnt = 20;
mutex m;
void fun() {
while (cnt > 0) {
m.lock();
if (cnt > 0) {
--cnt;
cout << cnt << endl;
}
m.unlock();
}
}
int main() {
thread th1(fun);
thread th2(fun);
th1.join();
th2.join();
return 0;
}

线程死锁及解决

但对变量加锁需要考虑特殊情况,如下

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
int cnt = 20;
mutex m;
void fun(int n)
{
try
{
while (cnt > 0)
{
m.lock();
if (n == 1)
throw("error");
if (cnt > 0)
{
--cnt;
cout << this_thread::get_id() << " " << cnt << endl;
}
m.unlock();
}
}
catch (const char* e)
{
cout << this_thread::get_id() << " " << e << endl;
}
}
int main()
{
thread th1(fun, 1);
thread th2(fun, 2);
th1.join();
th2.join();
return 0;
}

输出为

1
23352 error

上面的情况,就是出现了死锁,解决方法如下

可以使用 guard_lock

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
int cnt = 20;
mutex m;

void fun(int n)
{
try
{
while (cnt > 0)
{
lock_guard<mutex> lockGuard(m);
if (n == 1)
throw("error");
if (cnt > 0)
{
--cnt;
cout << this_thread::get_id() << " " << cnt << endl;
}
}
}
catch (const char* e)
{
cout << this_thread::get_id() << " " << e << endl;
}
}
int main()
{
thread th1(fun, 1);
thread th2(fun, 2);
th1.join();
th2.join();
return 0;
}

输出为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
23628 error
3848 19
3848 18
3848 17
3848 16
3848 15
3848 14
3848 13
3848 12
3848 11
3848 10
3848 9
3848 8
3848 7
3848 6
3848 5
3848 4
3848 3
3848 2
3848 1
3848 0

更多锁

更多有关于线程中锁的内容可查看C++-线程中的锁