《Linux C/C++服务器开发实践》之第3章 多线程基本编程

《Linux C/C++服务器开发实践》之第3章 多线程基本编程

    • 3.1 使用多线程的好处
    • 3.2 多线程编程的基本概念
      • 3.2.1 操作系统和多线程
      • 3.2.2 线程的基本概念
      • 3.2.3 线程的状态
      • 3.2.4 线程函数
      • 3.2.5 线程标识
      • 3.2.6 C++多线程开发的两种方式
    • 3.3 POSIX多线程开发
      • 3.3.1 线程的创建
        • 3.1.c
        • 3.2.c
        • 3.3.c
        • 3.4.c
        • 3.5.c
      • 3.3.2 线程的属性
        • 3.6.cpp
        • 3.7.cpp
        • 3.8.c
        • 3.9.c
        • 3.10.c
        • 3.11.c
      • 3.3.3 线程的结束
        • 3.12.c
        • 3.13.cpp
        • 3.14.cpp
        • 3.15.c
        • 3.16.c
      • 3.3.4 线程退出时的清理机会
        • 3.17.c
        • 3.18.c
        • 3.19.c
    • 3.4 C++11中的线程类
      • 3.4.1 线程创建
        • 3.20.cpp
        • 3.21.cpp
        • 3.22.cpp
        • 3.23.cpp
        • 3.24.cpp
        • 3.25.cpp
        • 3.26.cpp
        • 3.27.cpp
      • 3.4.2 线程标识符
        • 3.28.cpp
      • 3.4.3 当前线程
        • 3.29.cpp
        • 3.30.cpp
        • 3.31.cpp
    • 3.5 线程同步
      • 3.5.1 同步的基本概念
        • 3.32.cpp
        • 3.33.cpp
      • 3.5.2 临界资源和临界区
    • 3.6 POSIX线程同步
      • 3.6.1 互斥锁
        • 3.34.cpp
        • 3.35.cpp
      • 3.6.2 读写锁
        • 3.36.cpp
      • 3.6.3 条件变量
        • 3.37.c
    • 3.7 C++11/14线程同步
      • 3.7.1 基本互斥锁std::mutex
        • 3.38.cpp
      • 3.7.2 定时互斥锁std::timed_mutex
        • 3.39.cpp
    • 3.8 线程池
      • 3.8.1 线程池的定义
      • 3.8.2 使用线程池的原因
      • 3.8.3 POSIX线程池
        • 3.40_0.c
        • 3.40.cpp
      • 3.8.4 C++11线程池
        • 3.41.cpp
        • 3.41_0.cpp

3.1 使用多线程的好处

(1)响应速度更灵敏
多个任务不同线程执行,各自占用一段CPU时机,看起来任务同时进行,界面及时更新。

(2)运行效率更高
充分发挥cpu内核性能,增加运行效率。

(3)通信更高效
线程共享进程地址空间,比进程通信更高效和方便。

(4)开销更小
线程创建、切换等系统开销比进程更小。

3.2 多线程编程的基本概念

3.2.1 操作系统和多线程

操作系统分类:
(1)单进程、单线程,MS-DOS。
(2)多进程、单线程,多数UNIX(及类UNIX的Linux)。
(3)多进程、多线程,Win32(Windows NT/2000/XP/7/8/10等)、Solaris 2.x、OS/2。
(4)单进程、多线程,VxWorks。

3.2.2 线程的基本概念

CPU执行的是线程,线程是程序的最小执行单位,是操作系统分配CPU时间的最小实体。
线程共享进程的公共资源,如虚拟地址空间、全局变量等,线程可有自己私有资源,如堆栈、堆栈中定义的静态变量和动态变量、CPU寄存器的状态等(程序计数器、一组寄存器和线程栈,线程栈用于维护线程在执行代码时所需要的所有函数参数和局部变量)。

线程好处:
(1)线程创建、终止比进程更快;
(2)线程(尤其用户级)比进程切换更快;
(3)线程可以解决父子进程模型中子进程必须复制父进程地址空间的问题;
(4)线程对解决客户/服务器模型非常有效。

使用多线程情况:
(1)各任务相对独立;
(2)某些任务耗时较多;
(3)各任务有不同优先级;
(4)一些实时系统应用。

3.2.3 线程的状态

(1)就绪态
运行条件满足,等待处理器调度(调度策略)。等待原因:线程刚创建(刚创建线程不一定马上运行,一般先就绪)、刚重阻塞态恢复、其它线程抢占。

(2)运行态
占用着处理器运行。

(3)阻塞态
等待处理器之外的其它条件(I/O操作、互斥锁释放、条件变量的改变等)而无法运行的状态。

(4)终止态
线程函数运行结束或被其它线程取消。此时线程结束,但占用资源还未被回收,可以被重新复活。

3.2.4 线程函数

线程创建后进入运行态要执行的函数。
全局函数或类的静态函数。

void *ThreadProc(void *arg);

3.2.5 线程标识

句柄标识线程对象,ID标识线程本身。

3.2.6 C++多线程开发的两种方式

POSIX多线程API函数,传统;
C++自带线程类,新。

3.3 POSIX多线程开发

API函数 含义
pthread_create 创建线程
pthread_exit 终止自身线程
pthread_join 等待线程结束
pthread_self 线程ID
pthread_cancel 取消其它线程
pthread_kill 线程发送信号

3.3.1 线程的创建

int pthread_create(pthread_t *pid, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

pid指向线程ID,pthread_t是unsigned long int;
pthread_attr_t,线程属性结构,NULL使用默认属性;
start_routine指向线程函数地址;
arg指向传给线程函数的参数;
成功返回0
int pthread_join(pthread_t pid, void **value_ptr);

pid,线程ID;
value_ptr,获取线程退出值,可为NULL;
成功返回0。

pthread_join阻塞函数,让主线程挂起(即休眠,让出CPU),直到子线程退出,同时释放子线程所占资源。子线程退出后,主线程会收到系统信号,从休眠中恢复。
gcc -o test test.cpp -lpthread
3.1.c
#include 
#include 
#include  //sleep

void *thfunc(void *arg)
{
	printf("in thfunc\n");
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t tidp;
	int ret = pthread_create(&tidp, NULL, thfunc, NULL);
	if (ret)
	{
		printf("pthread_create failed: %d\n", ret);
		return -1;
	}

	sleep(1);
	printf("in main:thread is created\n");

	return 0;
}
3.2.c
#include 
#include 

void *thfunc(void *arg)
{
	int n = *(int *)(arg);

	printf("in thfunc: n=%d\n", n);
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t tidp;
	int n = 110;

	int ret = pthread_create(&tidp, NULL, thfunc, &n);
	if (ret)
	{
		printf("pthread_create failed: %d\n", ret);
		return -1;
	}

	pthread_join(tidp, NULL);
	printf("in main:thread is created\n");

	return 0;
}
3.3.c
#include 
#include 

void *thfunc(void *arg)
{
	char *str = (char *)arg;
	printf("in thfunc: str=%s\n", str); 
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t tidp;
	const char *str = "hello world";
	int ret = pthread_create(&tidp, NULL, thfunc, (void *)str);
	if (ret)
	{
		printf("pthread_create failed: %d\n", ret);
		return -1;
	}
	
	pthread_join(tidp, NULL);
	printf("in main:thread is created\n");

	return 0;
}
3.4.c
#include 
#include 

typedef struct
{
	int n;
	const char *str;
} MYSTRUCT;

void *thfunc(void *arg)
{
	MYSTRUCT *p = (MYSTRUCT *)arg;
	printf("in thfunc: n=%d, str=%s\n", p->n, p->str);
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t tidp;
	MYSTRUCT mystruct{110, "hello world"};
	int ret = pthread_create(&tidp, NULL, thfunc, (void *)&mystruct);
	if (ret)
	{
		printf("pthread_create failed:%d\n", ret);
		return -1;
	}

	pthread_join(tidp, NULL);
	printf("in main:thread is created\n");

	return 0;
}
3.5.c
#include 
#include 

int gn = 10; 

void *thfunc(void *arg)
{
	gn++;							
	printf("in thfunc: gn=%d,\n", gn);
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t tidp;
	int ret = pthread_create(&tidp, NULL, thfunc, NULL);
	if (ret)
	{
		printf("pthread_create failed:%d\n", ret);
		return -1;
	}
	pthread_join(tidp, NULL);	
	
	gn++;					
	printf("in main: gn=%d\n", gn);

	return 0;
}

3.3.2 线程的属性

分离状态(Detached State)、调度策略和参数(Scheduling Policy and Parameters)、作用域(Scope)、栈尺寸(Stack Size)、栈地址(Stack Address)、优先级(Priority)等。

union pthread_attr_t {
	char __size[__SIZEOF_PTHREAD_ATTR_T];
	long int __align;
};
#define _GNU_SOURCE
#include 
int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);
//获取线程属性,成功0。

默认线程属性,非分离、堆栈大小1MB,与父进程同样优先级。

int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
  1. 分离状态

线程终止方式,默认可连接。
非分离状态(可连接,joinable, PTHREAD_CREATE_JOINABLE),可以被其它线程收回资源和取消,不会主动释放资源(比如栈空间,僵尸线程),必须等待其它线程回收资源(pthread_join)。线程函数结束(return或pthread_exit)时,都不会释放线程占用的堆栈和线程描述符(8KB多)。父进程先于子线程退出,不会泄漏资源,会被init进程收养。线程不能被多个线程等待,第一个收到信号的线程成功返回,其余调用pthread_join的线程得到错误代码ESRCH。

可分离线程能独立(分离)出去,运行结束时,其资源立刻被系统回收。两种方式设置,pthread_detach和pthread_attr_setdetachstate(pthread_attr_t *attr, PTHREAD_CREATE_DETACHED)。

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
//PTHREAD_CREATE_DETACHED或PTHREAD_CREATE_JOINABLE
//设置线程分离状态属性。
3.6.cpp
#include 
#include 
#include 
#include  
using namespace std;

void *thfunc(void *arg)
{
	sleep(1);
	cout << ("sub thread is running\n");
	ofstream("tmp.file") << "out\n";

	//exit(5);
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_attr_t thread_attr;
	int res = pthread_attr_init(&thread_attr);
	if (res)
		cout << "pthread_attr_init failed:" << res << endl;

	res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
	if (res)
		cout << "pthread_attr_setdetachstate failed:" << res << endl;

	pthread_t thread_id;
	res = pthread_create(&thread_id, &thread_attr, thfunc, NULL);
	if (res)
		cout << "pthread_create failed:" << res << endl;
	cout << "main thread will exit\n";

	pthread_attr_destroy(&thread_attr);
	
	pthread_exit(NULL);
	
	//return 0;
}
3.7.cpp
#include 
#include 

using namespace std;

void *thfunc(void *arg)
{
	cout << ("sub thread is running\n");
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_attr_t thread_attr;
	int res = pthread_attr_init(&thread_attr);
	if (res)
		cout << "pthread_attr_init failed:" << res << endl;

	res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
	if (res)
		cout << "pthread_attr_setdetachstate failed:" << res << endl;

	pthread_t thread_id;
	res = pthread_create(&thread_id, &thread_attr, thfunc, NULL);
	if (res)
		cout << "pthread_create failed:" << res << endl;
	cout << "main thread will exit\n";

	pthread_attr_destroy(&thread_attr);

	pthread_exit(NULL);//主线程退出,进程不会退出,下面语句不会再执行。
	//进程资源会为其它线程保持打开,直到其它线程都终止。

	cout << "main thread has exited, this line will not run\n";
	return 0;
}
int pthread_detach(pthread_t thread);
//可连接线程转变为可分离线程(退出或pthread_exit后系统回收资源)
//EINVAL,非可连接线程
//ESRCH,线程未找到
//pthread_join后pthread_detach线程无作用
//pthread_detach后pthread_join出错
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
//获取分离状态
3.8.c
#ifndef _GNU_SOURCE
#define _GNU_SOURCE //pthread_getattr_np
#endif

#include 
#include 
#include 
#include 
#include 

#define handle_error_en(en, msg) \
	do                           \
	{                            \
		errno = en;              \
		perror(msg);             \
		exit(EXIT_FAILURE);      \
	} while (0)

static void *thread_start(void *arg)
{
	pthread_attr_t gattr;
	int s = pthread_getattr_np(pthread_self(), &gattr);
	if (s != 0)
		handle_error_en(s, "pthread_getattr_np");

	printf("Thread's detachstate attributes:\n");

	int i;
	s = pthread_attr_getdetachstate(&gattr, &i);
	if (s)
		handle_error_en(s, "pthread_attr_getdetachstate");
	printf("Detach state        = %s\n",
		   (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" : (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE"
																									   : "???");

	pthread_attr_destroy(&gattr);

	return 0;
}

int main(int argc, char *argv[])
{
	pthread_t thr;
	int s = pthread_create(&thr, NULL, &thread_start, NULL);
	if (s != 0)
	{
		handle_error_en(s, "pthread_create");
		return 0;
	}

	pthread_join(thr, NULL);

	return 0;
}
3.9.c
#ifndef _GNU_SOURCE
#define _GNU_SOURCE //pthread_getattr_np
#endif

#include 
#include 
#include 
#include 
#include 

static void *thread_start(void *arg)
{
	pthread_attr_t gattr;

	int s = pthread_getattr_np(pthread_self(), &gattr);
	if (s != 0)
		printf("pthread_getattr_np failed\n");

	int i;
	s = pthread_attr_getdetachstate(&gattr, &i);
	if (s)
		printf("pthread_attr_getdetachstate failed");
	printf("Detach state        = %s\n",
		   (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" : (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE"
																									   : "???");

	pthread_detach(pthread_self());

	s = pthread_getattr_np(pthread_self(), &gattr);
	if (s != 0)
		printf("pthread_getattr_np failed\n");

	s = pthread_attr_getdetachstate(&gattr, &i);
	if (s)
		printf(" pthread_attr_getdetachstate failed");
	printf("after pthread_detach, \nDetach state        = %s\n",
		   (i == PTHREAD_CREATE_DETACHED) ? "PTHREAD_CREATE_DETACHED" : (i == PTHREAD_CREATE_JOINABLE) ? "PTHREAD_CREATE_JOINABLE"
																									   : "???");

	pthread_attr_destroy(&gattr);

	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t thread_id;
	int s = pthread_create(&thread_id, NULL, &thread_start, NULL);
	if (s != 0)
	{
		printf("pthread_create failed\n");
		return 0;
	}
	pthread_exit(NULL); 

}
  1. 栈尺寸
    栈上的内存空间,如局部变量(尤其数组)、函数参数、返回地址等,动态分配内存(malloc)或全局变量等属于堆空间。
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
//获取栈尺寸(字节)
3.10.c
#ifndef _GNU_SOURCE
#define _GNU_SOURCE // pthread_getattr_np()
#endif

#include 
#include 
#include 
#include 
#include 
#include 

static void *thread_start(void *arg)
{
	pthread_attr_t gattr;
	int res = pthread_getattr_np(pthread_self(), &gattr);
	if (res)
		printf("pthread_getattr_np failed\n");

	size_t stack_size;
	res = pthread_attr_getstacksize(&gattr, &stack_size);
	if (res)
		printf("pthread_getattr_np failed\n");

	printf("Default stack size is %lu byte; minimum is %lu byte\n", stack_size, PTHREAD_STACK_MIN);

	pthread_attr_destroy(&gattr);

	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t thread_id;
	int s = pthread_create(&thread_id, NULL, &thread_start, NULL);
	if (s != 0)
	{
		printf("pthread_create failed\n");
		return 0;
	}
	pthread_join(thread_id, NULL);
	return 0;
}
  1. 调度策略
    操作系统管理线程如何占用CPU,就是线程调度。
    实时是操作系统对一些中断等的响应时效性非常高,非实时相反。VxWorks实时操作系统(Real-time Operating System,TSOS),Windows和Linux非实时操作系统(分时操作系统,Time-sharing Operating System,TSOS)。优先级控制CPU抢占,响应实时。

线程分实时和分时。线程调度策略:
(1)SCHED_OTHER
分时调度策略(轮转策略),默认,非实时。线程分配时间片,无优先级,按序运行。

(2)SCHED_FIFO
先来先服务调度策略,实时,支持优先级抢占。按序运行,直到更高优先级任务抢占。优先级范围1~99。

(3)SCHED_RR
时间片轮转(轮询)调度策略,实时,支持优先级抢占。线程分配特定时间片,用完后重新分配,保证相同优先级线程能够公平地调度。优先级范围1~99。

int sched_get_priority_min(int policty);
int sched_get_priority_max(int policty);
//SCHED_FIFO、SCHED_RR、SCHED_OTHER
3.11.c
#include 
#include 
#include 

int main()
{
	printf("Valid priority range for SCHED_OTHER: %d - %d\n",
		   sched_get_priority_min(SCHED_OTHER),
		   sched_get_priority_max(SCHED_OTHER));
	printf("Valid priority range for SCHED_FIFO: %d - %d\n",
		   sched_get_priority_min(SCHED_FIFO),
		   sched_get_priority_max(SCHED_FIFO));
	printf("Valid priority range for SCHED_RR: %d - %d\n",
		   sched_get_priority_min(SCHED_RR),
		   sched_get_priority_max(SCHED_RR));

	return 0;
}

3.3.3 线程的结束

线程结束方法:
(1)线程函数中调用pthread_exit;
不会导致C++对象被析构,可放心使用。

(2)线程所属进程结束,比如进程调用exit;
最好不用,线程函数中C++对象不会被销毁。

(3)线程函数执行结束,return;
最安全方式。

(4)线程被其它线程通知结束或取消。
中途停止线程,发送取消信号。

  1. 线程主动结束
    return或pthread_exit

主线程中调用pthread_exit(NULL);将结束主线程,但进程不会立即退出。

3.12.c
#include 
#include 
#include 
#include 
#include 

#define PTHREAD_NUM 2

void *thrfunc1(void *arg)
{
	static int count = 1;
	pthread_exit((void *)(&count));
}

void *thrfunc2(void *arg)
{
	static int count = 2;
	return (void *)(&count);
}

int main(int argc, char *argv[])
{
	pthread_t pid[PTHREAD_NUM];
	if (pthread_create(&pid[0], NULL, thrfunc1, NULL) != 0)
	{
		perror("create pid first failed");
		return -1;
	}
	if (pthread_create(&pid[1], NULL, thrfunc2, NULL))
	{
		perror("create pid second failed");
		return -1;
	}

	int *pRet1;
	if (pid[0] != 0)
	{
		pthread_join(pid[0], (void **)&pRet1);
		printf("get thread 0 exitcode: %d\n", *pRet1);
	}

	int *pRet2;
	if (pid[1] != 0)
	{
		pthread_join(pid[1], (void **)&pRet2);
		printf("get thread 1 exitcode: %d\n", *pRet2);
	}
	return 0;
}
  1. 线程被动结束
    pthread_kill或pthread_cancel。
int pthread_kill(pthread_t threadId, int signal);
//signal等于0用于探测线程是否存在
//ESRCH,线程不存在
//EINVAL,信号不合法

sigaction注册信号处理函数,默认会退出进程。

3.13.cpp
#include 
#include 
#include 
#include  //sleep
using namespace std;

static void on_signal_term(int sig)
{
	cout << "sub thread will exit" << endl;
	pthread_exit(NULL);
}

void *thfunc(void *arg)
{
	signal(SIGQUIT, on_signal_term);

	int tm = 50;
	while (true)
	{
		cout << "thrfunc--left:" << tm << " s--" << endl;
		sleep(1);
		tm--;
	}

	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t pid;
	int res = pthread_create(&pid, NULL, thfunc, NULL);

	sleep(5);

	pthread_kill(pid, SIGQUIT);
	pthread_join(pid, NULL);

	cout << "sub thread has completed, main thread will exit\n";

	return 0;
}
3.14.cpp
#include 
#include 
#include 
#include  //sleep
#include "errno.h"
using namespace std;

void *thfunc(void *arg)
{
	int tm = 50;
	while (1)
	//while (tm > 48)
	{
		cout << "thrfunc--left:" << tm << " s--" << endl;
		sleep(1);
		tm--;
	}
	return (void *)0;
}

int main(int argc, char *argv[])
{
	pthread_t pid;
	int res = pthread_create(&pid, NULL, thfunc, NULL);

	
	sleep(5);
	int kill_rc = pthread_kill(pid, 0);

	cout << kill_rc << endl;
	if (kill_rc == ESRCH)
		cout << "the specified thread did not exists or already quit\n";
	else if (kill_rc == EINVAL)
		cout << "signal is invalid\n";
	else
		cout << "the specified thread is alive\n";

	return 0;
}

pthread_cancel发送终止线程运行的请求,不一定成功。
发送终止线程运行的请求成功,系统并不会马上关闭被取消的线程,只有被取消的线程下次调用一些系统函数或C库函数(比如printf)或pthread_testcancel(死循环中,让内核有机会去检测是否需要取消当前线程)时,才会真正结束线程。被取消线程成功停止运行时,会返回常数PTHREAD_CANCELED(-1)。线程执行过程中,检测是否有未响应取消信号的地方,叫取消点,位于printf、pthread_testcancel、read/write、sleep等函数调用的地方。

3.15.c
#include 
#include 
#include 
#include  //sleep

void *thfunc(void *arg)
{
	printf("thread start-------- \n");
	int i=1;
	while(1)
		i++;

	return (void *)0;
}

int main()
{
	pthread_t tid;
	pthread_create(&tid, NULL, thfunc, NULL);
	sleep(1);

	pthread_cancel(tid);

	int *ret = NULL;
	pthread_join(tid, (void **)&ret);
	if (ret == PTHREAD_CANCELED)
		printf("thread has stopped,and exit code: -1\n"); //*ret,error
	else
		printf("some error occured");

	return 0;
}
3.16.c
#include 
#include 
#include 
#include  //sleep

void *thfunc(void *arg)
{
	printf("thread start-------- \n");
	int i=1;
	while(1){
		i++;
		pthread_testcancel();
	}

	return (void *)0;
}

int main()
{
	pthread_t tid;
	pthread_create(&tid, NULL, thfunc, NULL);
	sleep(1);

	pthread_cancel(tid);

	int *ret = NULL;
	pthread_join(tid, (void **)&ret);
	if (ret == PTHREAD_CANCELED)
		printf("thread has stopped,and exit code: -1\n");//*ret,error
	else
		printf("some error occured");

	return 0;
}

3.3.4 线程退出时的清理机会

需要线程退出时执行清理的机会,保证顺利地释放掉占用的资源,尤其是锁。

void pthread_cleanup_push(void (*routine)(void *), void *arg);
//压入清理函数routine。
/*
清理函数routine执行情况:
(1)线程主动结束,return或ptherad_exit
(2)pthread_cleanup_pop(1)
(3)其它线程函数调用pthread_cancel
*/

void pthread_cleanup_pop(int execute);
//弹出栈顶清理函数的同时,是否执行清理函数。
//0不执行,非0执行。

pthread_cleanup_push和pthread_cleanup_pop必须成对出现,否则语法错误。

void *thread1(void *arg){
	pthread_cleanup_push(clean_funnc, ...);
	
	pthread_mutex_lock(&mutex);

	sock = accept(...);
	
	pthread_mutex_unlock(&mutex);
	
	pthread_cleanup_pop(0);
	return NULL;
}
3.17.c
#include 
#include 
#include 
#include  //strerror

void mycleanfunc(void *arg)
{
	printf("mycleanfunc: %d\n", *((int *)arg));
}

void *thfrunc1(void *arg)
{
	int m = 1;
	printf("thfrunc1 comes \n");
	pthread_cleanup_push(mycleanfunc, &m);
	pthread_cleanup_pop(0);
	return (void *)0;//return 不会执行
}

void *thfrunc2(void *arg)
{
	int m = 2;
	printf("thfrunc2 comes \n");
	pthread_cleanup_push(mycleanfunc, &m);
	pthread_exit((void *)0);
	pthread_cleanup_pop(0);
}

int main(void)
{
	pthread_t pid1;
	int res = pthread_create(&pid1, NULL, thfrunc1, NULL);
	if (res)
	{
		printf("pthread_create failed: %s\n", strerror(res));
		exit(1);
	}
	pthread_join(pid1, NULL);

	pthread_t pid2;
	res = pthread_create(&pid2, NULL, thfrunc2, NULL);
	if (res)
	{
		printf("pthread_create failed: %s\n", strerror(res));
		exit(1);
	}
	pthread_join(pid2, NULL);

	printf("main over\n");
	return 0;
}
3.18.c
#include 
#include 
#include 
#include  //strerror
 
void mycleanfunc(void *arg)
{
	printf("mycleanfunc: %d\n", *((int *)arg));						 
}

void *thfrunc1(void *arg)
{
	int m=1, n=2;
	printf("thfrunc1 comes \n");
	pthread_cleanup_push(mycleanfunc, &m); 
	pthread_cleanup_push(mycleanfunc, &n); 
	pthread_cleanup_pop(1);
	pthread_exit(0);
	pthread_cleanup_pop(0);
}
  
int main(void)
{
	pthread_t pid1 ;
	int res = pthread_create(&pid1, NULL, thfrunc1, NULL);
	if (res) 
	{
		printf("pthread_create failed: %s\n", strerror(res));
		exit(1);
	}
	pthread_join(pid1, NULL);
	
	printf("main over\n");
	return 0;
}
3.19.c
#include   
#include   
#include   
#include  //sleep

void mycleanfunc(void *arg) 
{
	printf("mycleanfunc: %d\n", *((int *)arg));						 
}
 
void *thfunc(void *arg)  
{  
	int i = 1;  
	printf("thread start-------- \n"); 
	pthread_cleanup_push(mycleanfunc, &i);
	while (1)  
	{
		i++;  
		printf("i=%d\n", i);
	}	
	printf("this line will not run\n");
	pthread_cleanup_pop(0);
	
	return (void *)0;  
}

int main()  
{  
	pthread_t tid;  
	pthread_create(&tid, NULL, thfunc, NULL); 
	sleep(1);  
          
	pthread_cancel(tid); 
	
	int *ret = NULL;  
	pthread_join(tid, (void **)&ret); 
	if (ret == PTHREAD_CANCELED)
		printf("thread has stopped, and exit code: -1\n"); 
	else
		printf("some error occured");

          
	return 0;  
}

3.4 C++11中的线程类

  • atomic
    std::atomic和std::atomic_flag

  • thread
    std::thread和std::this_thread

  • mutex
    std::mutex、std::lock_guard、std::unique_lock

  • condition_variable
    std::condition_variable和std::condition_variable_any

  • future
    std::promise、std::package_task、std::future、std::shared_future、std::async

std::thread成员函数 说明(public访问方式)
thread 4种构造函数
get_id 线程id
joinable 是否可连接
join 连接,阻塞函数
native_handle 操作系统相关的原生线程句柄(需要本地库支持)
swap 线程交换
detach 分离线程
g++ -o test test.cpp -lpthread -sd=c++11

3.4.1 线程创建

  1. 默认构造函数
thread();
//线程不会马上运行
3.20.cpp
#include 
#include 

#include 	// std::chrono::seconds
#include  // std::cout
#include 	// std::thread, std::this_thread::sleep_for
using namespace std;

void thfunc(int n)
{
	std::cout << "thfunc:" << n << endl;
}

int main(int argc, const char *argv[])
{
	std::thread threads[5];
	std::cout << "create 5 threads...\n";
	for (int i = 0; i < 5; i++)
		threads[i] = std::thread(thfunc, i + 1);

	for (auto &t : threads)
		t.join();

	std::cout << "All threads joined.\n";

	return EXIT_SUCCESS;
}
  1. 初始化构造函数
    将线程函数指针和参数(若存在)线程类的构造函数中,线程会立即开始执行。
templace <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);
void join();
3.21.cpp
#include   
#include   
      
using namespace std;  
      
void th_function()  
{  
	std::cout << "i am c++11 thread func" << std::endl;  
}  
      
int main(int argc, char *argv[])  
{  
	std::thread t(th_function);  
	t.join();  
      
	return 0;  
}  
3.22.cpp
#include 
#include 
using namespace std;

void thfunc(int n)
{
	cout << "thfunc: " << n << "\n";
}

int main(int argc, char *argv[])
{
	thread t(thfunc, 1);
	t.join();

	return 0;
}
3.23.cpp
#include 
#include 
using namespace std;

void thfunc(char *s)
{
	cout << "thfunc: " << s << "\n";
}

int main(int argc, char *argv[])
{
	char s[] = "boy and girl";
	thread t(thfunc, s);
	t.join();

	return 0;
}
3.24.cpp
#include 
#include 
using namespace std;

typedef struct
{
	int n;
	const char *str;
} MYSTRUCT;

void thfunc(void *arg)
{
	MYSTRUCT *p = (MYSTRUCT *)arg;
	cout << "in thfunc: n=" << p->n << ", str=" << p->str << endl;
}

int main(int argc, char *argv[])
{
	MYSTRUCT mystruct{110, "hello world"};

	thread t(thfunc, &mystruct);
	t.join();

	return 0;
}
3.25.cpp
#include 
#include 
using namespace std;

void thfunc(int n, int m, int *k, char s[])
{
	cout << "in thfunc: n=" << n << ", m=" << m << ", k=" << *k << "\nstr=" << s << endl;
	*k = 5000;
}

int main(int argc, char *argv[])
{
	int n = 110, m = 200, k = 5;
	char str[] = "hello world";

	thread t(thfunc, n, m, &k, str);
	t.join();

	cout << "k=" << k << endl;

	return 0;
}
void detach();
3.26.cpp
#include 
#include 
using namespace std;

void thfunc(int n, int m, int *k, char s[])
{
	cout << "in thfunc: n=" << n << ", m=" << m << ", k=" << *k << "\nstr=" << s << endl;
	*k = 5000;
}

int main(int argc, char *argv[])
{
	int n = 110, m = 200, k = 5;
	char str[] = "hello world";

	thread t(thfunc, n, m, &k, str);
	t.detach();

	cout << "k=" << k << endl;
	pthread_exit(NULL);

	cout << "this line will not run" << endl;
	return 0;
}
  1. 移动构造函数
thread(thread&& x);
3.27.cpp
#include 
#include 

using namespace std;

void fun(int &n)
{
	cout << "fun: " << n << "\n";
	n += 20;
	this_thread::sleep_for(chrono::milliseconds(10));
}

int main()
{
	int n = 0;

	cout << "n=" << n << '\n';
	n = 10;
	
	thread t1(fun, ref(n));
	thread t2(move(t1));
	t2.join();

	cout << "n=" << n << '\n';
	return 0;
}

3.4.2 线程标识符

thread::id get_id()
3.28.cpp
#include  // std::cout
#include 	// std::thread, std::thread::id, std::this_thread::get_id
using namespace std;

thread::id main_thread_id = this_thread::get_id();

void is_main_thread()
{
	if (main_thread_id == this_thread::get_id())
		std::cout << "This is the main thread.\n";
	else
		std::cout << "This is not the main thread.\n";
}

int main()
{
	is_main_thread();

	thread th(is_main_thread);
	th.join();

	return 0;
}

3.4.3 当前线程

this_thread引用当前线程。

  1. 让出CPU时间
//线程放弃执行,回到就绪态
void yield();//让出线程CPU时间片,让其它线程有机会执行。
3.29.cpp

#include  // std::cout
#include 	// std::thread, std::this_thread::yield
#include 	// std::atomic
using namespace std;

atomic<bool> ready(false);

void thfunc(int id)
{
	while (!ready)
		this_thread::yield();

	for (volatile int i = 0; i < 1000000; ++i)
	{
	}
	cout << id << ",";
}

int main()
{
	cout << "race of 10 threads that count to 1 million:\n";

	thread threads[10];
	for (int i = 0; i < 10; ++i)
		threads[i] = thread(thfunc, i);

	ready = true;
	for (auto &th : threads)
		th.join();

	cout << '\n';

	return 0;
}
  1. 线程暂停一段时间
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);

template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
3.30.cpp
#include  // std::cout
#include 	// std::this_thread::sleep_until
#include 	// std::chrono::system_clock
#include 	// std::time_t, std::tm, std::localtime, std::mktime
#include 
#include 
using namespace std;

void getNowTime()
{
	timespec time;
	clock_gettime(CLOCK_REALTIME, &time);

	struct tm nowTime;
	localtime_r(&time.tv_sec, &nowTime);
	
	printf("%04d-%02d-%02d %02d:%02d:%02d\n",
		   nowTime.tm_year + 1900,
		   nowTime.tm_mon + 1,
		   nowTime.tm_mday,
		   nowTime.tm_hour,
		   nowTime.tm_min,
		   nowTime.tm_sec);
}

int main()
{
	using std::chrono::system_clock;
	std::time_t tt = system_clock::to_time_t(system_clock::now());

	struct std::tm *ptm = std::localtime(&tt);
	getNowTime();
	cout << "Waiting for the next minute to begin...\n";

	++ptm->tm_min;
	ptm->tm_sec = 0;

	this_thread::sleep_until(system_clock::from_time_t(mktime(ptm)));
	getNowTime();

	return 0;
}
3.31.cpp
#include  // std::cout, std::endl
#include 	// std::this_thread::sleep_for
#include 	// std::chrono::seconds

int main()
{
	std::cout << "countdown:\n";
	for (int i = 5; i > 0; --i)
	{
		std::cout << i << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
	std::cout << "Lift off!\n";

	return 0;
}

3.5 线程同步

保证共享资源的稳定性,使用线程同步机制调整多个线程的执行顺序。只有拥有锁的线程才能操作共享资源,其它线程等待。
异步是当调用或请求发送给被调用者时,调用者不用等待结果返回而继续当前处理。实现异步机制的方式有多线程、中断和消息等。

3.5.1 同步的基本概念

同步机制消除并发和异步机制带来的线程资源竞争无序性的复杂度,实现线程间有序正确地共享数据,以一致的顺序执行一组操作。

3.32.cpp
#include 
#include 
#include 
#include 
#include 
#include 

int gcn;

void *thread_1(void *arg)
{
	for (int j = 0; j < 10000000; j++)
		gcn++;
	pthread_exit((void *)0);
}

void *thread_2(void *arg)
{
	for (int j = 0; j < 10000000; j++)
		gcn++;
	pthread_exit((void *)0);
}

int main(void)
{
	for (int j = 0; j < 10; j++)
	{
		gcn = 0;

		pthread_t th1, th2;

		int err = pthread_create(&th1, NULL, thread_1, (void *)0);
		if (err != 0)
		{
			printf("create new thread error:%s\n", strerror(err));
			exit(0);
		}
		err = pthread_create(&th2, NULL, thread_2, (void *)0);
		if (err != 0)
		{
			printf("create new thread error:%s\n", strerror(err));
			exit(0);
		}

		err = pthread_join(th1, NULL);
		if (err != 0)
		{
			printf("wait thread done error:%s\n", strerror(err));
			exit(1);
		}
		err = pthread_join(th2, NULL);
		if (err != 0)
		{
			printf("wait thread done error:%s\n", strerror(err));
			exit(1);
		}
		printf("gcn=%d\n", gcn);
	}

	return 0;
}
3.33.cpp
#include 
#include 
#include 

#include 
using namespace std;
 
int a = 200;
int b = 100;
 
void* ThreadA(void*)
{
	while (1)
	{
		a -= 50; 
		b += 50;
	}
}
 
void* ThreadB(void*)
{
	while (1)
	{
		cout <<a+b<<endl;
		sleep(1);    
	}
}
 
int main()
{
	pthread_t tida, tidb;
 
	pthread_create(&tida, NULL, ThreadA, NULL);
	pthread_create(&tidb, NULL, ThreadB, NULL);
	//pthread_join(tida, NULL);
	pthread_join(tidb, NULL);

	return 1;
}

3.5.2 临界资源和临界区

临界资源,指一次仅允许一个线程使用的共享资源,各线程应该互斥对其访问。每个线程中访问临界资源的那段代码称为临界(区|段)(Critical Section)。

3.6 POSIX线程同步

3.6.1 互斥锁

  1. 互斥锁的概念
    线程同步的一种机制,用来保护多线程的共享资源。初始化一个互斥锁,进入临界区之前把互斥锁加锁(防止其它线程进入临界区),退出临界区的时候把互斥锁解锁(其它线程有机会进入临界区),最后不用互斥锁的时候销毁它。
#include 
pthread_mutex_t mutex;
  1. 互斥锁的初始化
//函数初始化,动态方式,需要销毁
//restrict,只用于限定指针,告知编译器,只能通过该指针修改期指向内容。
//帮助编译器进行代码优化,生成更有效率的汇编代码。
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//宏PTHREAD_MUTEX_INITIALIZER静态初始化,常量初始化,不需要销毁
#define PTHREAD_MUTEX_INITIALIZER \
	{{0,0,0,0,0,{0}}}
	
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
//或者
pthread_mutex_t pmutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
pthread_mutex_init(pmutex , NULL);

  1. 互斥锁的上锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  1. 互斥锁的销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
3.34.cpp
#include 
#include 
#include 
#include 
#include 
#include 

int gcn;

pthread_mutex_t mutex;

void *thread_1(void *arg)
{
	for (int j = 0; j < 10000000; j++)
	{
		pthread_mutex_lock(&mutex);
		gcn++;
		pthread_mutex_unlock(&mutex);
	}
	pthread_exit((void *)0);
}

void *thread_2(void *arg)
{
	for (int j = 0; j < 10000000; j++)
	{
		pthread_mutex_lock(&mutex);
		gcn++;
		pthread_mutex_unlock(&mutex);
	}
	pthread_exit((void *)0);
}

int main(void)
{
	pthread_mutex_init(&mutex, NULL); 
	for (int j = 0; j < 10; j++)
	{
		gcn = 0;

		pthread_t th1, th2;

		int err = pthread_create(&th1, NULL, thread_1, (void *)0);
		if (err != 0)
		{
			printf("create new thread error:%s\n", strerror(err));
			exit(0);
		}
		err = pthread_create(&th2, NULL, thread_2, (void *)0);
		if (err != 0)
		{
			printf("create new thread error:%s\n", strerror(err));
			exit(0);
		}

		err = pthread_join(th1, NULL);
		if (err != 0)
		{
			printf("wait thread done error:%s\n", strerror(err));
			exit(1);
		}
		err = pthread_join(th2, NULL);
		if (err != 0)
		{
			printf("wait thread done error:%s\n", strerror(err));
			exit(1);
		}
		printf("gcn=%d\n", gcn);
	}

	pthread_mutex_destroy(&mutex);

	return 0;
}
3.35.cpp
#include 
#include 
#include 

#include 
using namespace std;

int a = 200;
int b = 100;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *ThreadA(void *)
{

	while (1)
	{
		pthread_mutex_lock(&lock);
		a -= 50;
		b += 50;
		pthread_mutex_unlock(&lock);
	}
}

void *ThreadB(void *)
{
	while (1)
	{
		pthread_mutex_lock(&lock);
		cout << a + b << endl;
		pthread_mutex_unlock(&lock);
		sleep(1);
	}
}

int main()
{
	//pthread_mutex_init(&lock, NULL);

	pthread_t tida, tidb;
	pthread_create(&tida, NULL, ThreadA, NULL);
	pthread_create(&tidb, NULL, ThreadB, NULL);
	pthread_join(tida, NULL);
	pthread_join(tidb, NULL);

	//pthread_mutex_destroy(&lock);

	return 1;
}

3.6.2 读写锁

  1. 读写锁的概念
    不修改临界资源的情况下,可以多个线程同时读取共享变量的值。
    资源的独占式访问,称为写操作;资源的共享式访问,称为读操作。
    读锁锁定临界区时,其它线程可用读锁进入临界区,并行读取共享资源,此时写锁线程会阻塞;
    写锁锁定临界区时,其它线程无论读锁还是写锁都会阻塞。
#include 
pthread_rwlock_t rwlock;
  1. 读写锁的初始化
//宏PTHREAD_RWLOCK_INITIALIZER静态初始化,常量初始化,不需要销毁
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
//函数初始化,动态方式,需要销毁
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
//或者
pthread_rwlock_t *prwlock = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t ));
pthread_rwlock_init(prwlock , NULL);
  1. 读写锁的上锁和解锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
//若上锁,不阻塞,立即返回EBUSY
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
//若上锁,不阻塞,立即返回EBUSY
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

//规定时间等待读写锁,等不到返回ETIMEDOUT
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *restrict abs_timeout);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *restrict abs_timeout);

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
  1. 读写锁的销毁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
3.36.cpp
#include 
#include 
#include 
#include 
#include 
#include 

#include 
using namespace std;

int gcn = 0;

pthread_mutex_t mutex;
pthread_rwlock_t rwlock;

void *thread_1(void *arg)
{
	volatile int a;
	for (int j = 0; j < 10000000; j++)
	{
		pthread_mutex_lock(&mutex);
		a = gcn;
		pthread_mutex_unlock(&mutex);
	}
	pthread_exit((void *)0);
}

void *thread_2(void *arg)
{
	volatile int b;
	for (int j = 0; j < 10000000; j++)
	{
		pthread_mutex_lock(&mutex);
		b = gcn;
		pthread_mutex_unlock(&mutex);
	}
	pthread_exit((void *)0);
}

void *thread_3(void *arg)
{
	volatile int a;
	for (int j = 0; j < 10000000; j++)
	{
		pthread_rwlock_rdlock(&rwlock);
		a = gcn;
		pthread_rwlock_unlock(&rwlock);
	}
	pthread_exit((void *)0);
}

void *thread_4(void *arg)
{
	volatile int b;
	for (int j = 0; j < 10000000; j++)
	{
		pthread_rwlock_rdlock(&rwlock);
		b = gcn;
		pthread_rwlock_unlock(&rwlock);
	}
	pthread_exit((void *)0);
}

int mutextVer()
{
	pthread_mutex_init(&mutex, NULL);

	struct timeval start;
	gettimeofday(&start, NULL);

	pthread_t th1, th2;
	int err = pthread_create(&th1, NULL, thread_1, (void *)0);
	if (err != 0)
	{
		printf("create new thread error:%s\n", strerror(err));
		exit(0);
	}
	err = pthread_create(&th2, NULL, thread_2, (void *)0);
	if (err != 0)
	{
		printf("create new thread error:%s\n", strerror(err));
		exit(0);
	}

	err = pthread_join(th1, NULL);
	if (err != 0)
	{
		printf("wait thread done error:%s\n", strerror(err));
		exit(1);
	}
	err = pthread_join(th2, NULL);
	if (err != 0)
	{
		printf("wait thread done error:%s\n", strerror(err));
		exit(1);
	}

	struct timeval end;
	gettimeofday(&end, NULL);

	pthread_mutex_destroy(&mutex);

	long long total_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
	total_time /= 1000;
	printf("total mutex time is %lld ms\n", total_time);

	return 0;
}

int rdlockVer()
{
	pthread_rwlock_init(&rwlock, NULL);

	struct timeval start;
	gettimeofday(&start, NULL);

	pthread_t th1, th2;
	int err = pthread_create(&th1, NULL, thread_3, (void *)0);
	if (err != 0)
	{
		printf("create new thread error:%s\n", strerror(err));
		exit(0);
	}
	err = pthread_create(&th2, NULL, thread_4, (void *)0);
	if (err != 0)
	{
		printf("create new thread error:%s\n", strerror(err));
		exit(0);
	}

	err = pthread_join(th1, NULL);
	if (err != 0)
	{
		printf("wait thread done error:%s\n", strerror(err));
		exit(1);
	}
	err = pthread_join(th2, NULL);
	if (err != 0)
	{
		printf("wait thread done error:%s\n", strerror(err));
		exit(1);
	}

	struct timeval end;
	gettimeofday(&end, NULL);

	pthread_rwlock_destroy(&rwlock);

	long long total_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
	total_time /= 1000;
	printf("total mutex time is %lld ms\n", total_time);

	return 0;
}

int main()
{
	mutextVer();
	rdlockVer();
	return 0;
}

3.6.3 条件变量

  1. 条件变量的概念
    条件变量(Condition Variable),让线程因等待“条件变量的条件而挂起”,其它线程在条件成立后向挂起的线程发送条件成立的信号。
    条件变量联合互斥锁使用,用于防止线程间竞争。条件变量常用于多线程间共享数据状态变化的通信中,当一个线程的行为依赖于另外一个线程对共享数据状态的改变时,就可以使用条件变量来同步它们。
    经典的生产者消费者(Producer-Consumer)问题,即有界缓冲区(Bounded Buffer)问题。线程共享公共的固定的缓冲区,生产者线程向缓冲区写入数据,消费者线程从缓冲区读取数据。缓冲区满时,生产者休眠,等待消费者从缓冲区取走数据后再去唤醒它;缓冲区空时,消费者休眠,等待生产者向缓冲区写入数据后再去唤醒它。
pthread_mutex_t mutex;
#define N 100
int count = 0;

//生产者线程
void procedure() {
	int item;
	while(1) {
		item = produce_item();	//生成数据项
		if(count == N)	//缓冲区满了
			sleep();
		pthread_mutex_lock(&mutex);
		insert_item(item);	//数据项放入缓冲区
		count = count + 1;
		pthread_mutex_unlock(&mutex);
		if(count == 1)	//消费者等待
			wakeup(consumer);	//唤醒消费者
	}
}

//消费者线程
void consumer() {
	int item;
	while(1) {
		if(count == 0)	//缓冲区空了
			sleep();
		
		pthread_mutex_lock(&mutex);
		item = remove_item();	//取走数据项
		count = count - 1;
		pthread_mutex_unlock(&mutex);
		if(count == N - 1)	//缓冲区有空槽
			wakeup(procedure);	//唤醒生成者
	}
}

消费者从解锁到休眠这段代码有可能被打断,而条件变量将互斥锁释放到休眠当作原子操作,不容打断。

  1. 条件变量的初始化
    常量(静态)初始化,不需要销毁
pthread_cont_t cond = PTHREAD_COND_INITIALLER;

动态初始化,需要销毁

pthread_cont_t cond;
pthread_cond_init(&cond, NULL);

//和

pthread_cont_t *pcond = (pthread_cont_t *)malloc(sizeof(pthread_cont_t));
pthread_cond_init(pcond, NULL);
#include 

typedef struct {
	pthread_mutex_t mutex;
	pthread_cond_t cond;
	int value;
} my_struct_t ;

my_struct_t data = {
	PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0
};

int main() {
	return 0;
}
  1. 等待条件变量
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

typedef struc timespec {
	time_t tv_sec;	//秒
	long tv_nsex;	//纳秒
} timespec_t ;
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
lock(mutex)
while(condition is false)
	cond_wait(cond, mutex, timeout)
dosomething()
unlock(mutex)

条件变量必须和互斥锁联合使用。能够保证互斥锁解锁到线程被条件变量阻塞,互斥锁上锁到线程被唤醒都是原子操作。
while循环用于判断是否虚假唤醒(Spurious Wakeups),条件不一定满足。

  1. 唤醒等待条件变量的线程
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

  1. 条件变量的销毁
int pthread_cond_destroy(pthread_cond_t *cond);
3.37.c
#include 
#include 
#include 
#include 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int i = 1;

void *thread1(void *junk) {
	while(i <= 20) {
		pthread_mutex_lock(&mutex);
		if(i%3 == 0)
			pthread_cond_signal(&cond);
		else
			print("thread1: %d\n", i);
		pthread_mutex_unlock(&mutex);
		sleep(1); 
		i++;
	}
}

void *thread2(void *junk) {
	while(i < 20) {
		pthread_mutex_lock(&mutex);
		if(i%3 != 0)
			pthread_cond_wait(&cond, &mutex);
		print("thread2: %d\n", i);
		pthread_mutex_unlock(&mutex);
		sleep(1); 
		i++;
	}
}

int main() {
	//pthread_mutex_init(&mutex, NULL);
	//pthread_cond_init(&cond, NULL);
	pthread_t t_a;
	pthread_t t_b;

	pthread_cteate(&t_a, NULL, thread2, NULL);
	pthread_cteate(&t_b, NULL, thread1, NULL);
	pthread_join(t_b, NULL);

	//pthread_mutex_destroy(&mutex);
	//pthread_cond_destroy(&cond);
	return 0;
}

3.7 C++11/14线程同步

mutex(基本互斥锁)recursive_mutex(递归互斥锁)timed_mutex(定时互斥锁)recursive_timed_mutex(定时递归互斥锁)

lock、try_lock、unlock

3.7.1 基本互斥锁std::mutex

std::mutex成员函数 说明
mutex 构造函数
lock 上锁
try_lock 尝试上锁
native_handle 本地互斥锁句柄
void lock();
void unlock();
3.38.cpp
#include  // std::cout
#include 	// std::thread
#include 	// std::mutex

volatile int counter(0); // non-atomic counter
std::mutex mtx;			 // locks access to counter

void thrfunc()
{
	for (int i = 0; i < 10000; ++i)
	{
		mtx.lock();
		++counter;
		mtx.unlock();
	}
}

int main(int argc, const char *argv[])
{
	std::thread threads[10];

	for (int i = 0; i < 10; ++i)
		threads[i] = std::thread(thrfunc);

	for (auto &th : threads)
		th.join();
		
	std::cout << "count to " << counter << " successfully \n";

	return 0;
}

3.7.2 定时互斥锁std::timed_mutex

增加定时功能

std::timed_mutex成员函数 说明
timed_mutex 构造函数
lock 上锁
try_lock 尝试上锁
try_lock_for 一段时间尝试上锁
try_lock_until 时间点前尝试上锁
native_handle 本地互斥锁句柄
3.39.cpp
#include  // std::cout
#include 	// std::thread
#include 	// std::mutex

volatile int counter(0);
std::timed_mutex mtx;

void thrfunc()
{
	for (int i = 0; i < 10000; ++i)
	{
		if (mtx.try_lock_for(std::chrono::milliseconds(10)))
		{
			++counter;
			mtx.unlock();
		}
		else
			std::cout << "try_lock false\n";
	}
}

int main(int argc, const char *argv[])
{
	std::thread threads[10];

	for (int i = 0; i < 10; ++i)
		threads[i] = std::thread(thrfunc);

	for (auto &th : threads)
		th.join();

	std::cout << "count to " << counter << " successfully \n";

	return 0;
}

3.8 线程池

3.8.1 线程池的定义

一堆已经创建好了的线程,初始时处于空闲等待状态,当需要处理新任务时,线程池中取出一个空闲等待的线程来处理该任务,任务处理完毕后该线程放回池中(线程状态设置为空闲)。

3.8.2 使用线程池的原因

与进程比较,线程的创建和销毁是轻量级的(开销较小),但大量创建和销毁线程时,开销合在一起就比较大。线程池可以线程复用,避免无谓的开销。

3.8.3 POSIX线程池

c 线程池

3.40_0.c
#include 
#include 
#include 
#include 

typedef struct
{
    void (*function)(void *arg);
    void *arg;
} Task;

typedef struct
{
    Task *taskQ;       // 任务队列
    int queueCapacity; // 容量
    int queueSize;     // 当前任务个数
    int queueFront;    // 队头 -> 取数据
    int queueRear;     // 队尾 -> 放数据

    pthread_t managerID;       // 管理者线程ID
    pthread_t *threadIDs;      // 工作的线程ID
    int minNum;                // 最小线程数量
    int maxNum;                // 最大线程数量
    int busyNum;               // 忙的线程的个数
    int liveNum;               // 存活的线程的个数
    int exitNum;               // 要销毁的线程个数,= liveNum - busyNum
    pthread_mutex_t mutexPool; // 锁整个的线程池
    pthread_mutex_t mutexBusy; // 锁busyNum变量
    pthread_cond_t notFull;    // 任务队列是不是满了
    pthread_cond_t notEmpty;   // 任务队列是不是空了

    int shutdown; // 是不是要销毁线程池, 销毁为1, 不销毁为0
} ThreadPool;

// 当前工作线程个数
int threadPoolBusyNum(ThreadPool *pool)
{
    pthread_mutex_lock(&pool->mutexBusy);
    int busyNum = pool->busyNum;
    pthread_mutex_unlock(&pool->mutexBusy);
    return busyNum;
}

// 当前活着的线程的个数
int threadPoolAliveNum(ThreadPool *pool)
{
    pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->liveNum;
    pthread_mutex_unlock(&pool->mutexPool);
    return aliveNum;
}

// 线程池退出
void threadExit(ThreadPool *pool)
{
    pthread_t tid = pthread_self();
    pthread_mutex_lock(&pool->mutexPool);
    for (int i = 0; i < pool->maxNum; i++)
    {
        if (pool->threadIDs[i] == tid)
        {
            pool->threadIDs[i] = 0;
            pool->liveNum--;
            printf("threadExit() called, %ld exiting...\n", tid);
            break;
        }
    }
    pthread_mutex_unlock(&pool->mutexPool);

    pthread_exit(NULL);
}

// 工作的线程(消费者线程)任务函数
void *worker(void *arg)
{
    ThreadPool *pool = (ThreadPool *)arg;
    while (1)
    {
        pthread_mutex_lock(&pool->mutexPool);

        // 当前任务队列是否为空
        while (pool->queueSize == 0 && !pool->shutdown)
        {
            // 阻塞工作线程
            pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);

            // 判断是否用销毁线程
            if (pool->exitNum > 0) // 启动线程冗余
            {
                pool->exitNum--;
                if (pool->liveNum > pool->minNum)
                {
                    pool->liveNum--;
                    pthread_mutex_unlock(&pool->mutexPool);
                    threadExit(pool);
                }
            }
        }

        // 判断线程池是否被关闭
        if (pool->shutdown)
        {
            pthread_mutex_unlock(&pool->mutexPool);
            threadExit(pool);
        }

        // 从任务队列中取出一个任务
        Task task;
        task.function = pool->taskQ[pool->queueFront].function;
        task.arg = pool->taskQ[pool->queueFront].arg;

        // 移动头节点
        pool->queueFront = (pool->queueFront + 1) % pool->queueCapacity;
        pool->queueSize--;

        // 解锁
        pthread_mutex_unlock(&pool->mutexPool);
        pthread_cond_signal(&pool->notFull); // 通知线程池可以添加任务

        printf("thread %ld start working...\n", pthread_self());
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum++;
        pthread_mutex_unlock(&pool->mutexBusy);

        // 执行
        task.function(task.arg);
        free(task.arg);
        task.arg = NULL;

        printf("thread %ld end working...\n", pthread_self());
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum--;
        pthread_mutex_unlock(&pool->mutexBusy);
    }

    threadExit(pool);
    // return NULL;
}

// 管理者线程任务函数
// 动态增删线程数
void *manager(void *arg)
{
    ThreadPool *pool = (ThreadPool *)arg;
    while (!pool->shutdown)
    {
        // 3s检查一次
        sleep(3);

        // 取出线程池任务的数量和当前线程的数量
        pthread_mutex_lock(&pool->mutexPool);
        int queueSize = pool->queueSize;
        int liveNum = pool->liveNum;
        printf("liveNum = %d\n", liveNum);
        pthread_mutex_unlock(&pool->mutexPool);

        // 取出忙的线程的数量
        pthread_mutex_lock(&pool->mutexBusy);
        int busyNum = pool->busyNum;
        printf("busyNum = %d\n", busyNum);
        pthread_mutex_unlock(&pool->mutexBusy);

        // 添加线程
        // 任务的个数 > 成活的线程个数 && 存活的线程数 < 最大线程数
        if (queueSize > liveNum && liveNum < pool->maxNum)
        {
            pthread_mutex_lock(&pool->mutexPool);
            for (int i = 0; i < pool->maxNum && pool->liveNum < pool->maxNum; i++)
            {
                if (pool->threadIDs[i] == 0)
                {
                    pthread_create(&pool->threadIDs[i], NULL, worker, pool); // 创建新线程
                    pool->liveNum++;
                }
            }
            pthread_mutex_unlock(&pool->mutexPool);
        }

        // 销毁线程
        // 条件是:忙的线程*2 < 存活的线程数 && 存活的线程 > 最小线程数
        // 我觉得,释放多余内存
        if (busyNum * 2 < liveNum && liveNum > pool->minNum)
        {
            pthread_mutex_lock(&pool->mutexPool);
            int NUMBER = pool->liveNum - pool->busyNum;
            pool->exitNum = NUMBER;
            pthread_mutex_unlock(&pool->mutexPool);

            // 发信号让线程自杀,具体实现就是每个线程的有一个销毁判断
            // 每次销毁一个,pool->exitNum--,直到为0
            for (int i = 0; i < NUMBER; i++)
                pthread_cond_signal(&pool->notEmpty);
        }
    }

    pthread_cond_broadcast(&pool->notEmpty);
    return NULL;
}

// 创建线程池并初始化
ThreadPool *threadPoolCreate(int min, int max, int queueSize)
{
    ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
    do
    {
        if (pool == NULL)
        {
            printf("malloc ThreadPool failed\n");
            break;
        }

        pool->threadIDs = (pthread_t *)malloc(sizeof(pthread_t) * max);
        if (pool->threadIDs == NULL)
        {
            printf("malloc threadIDs failed\n");
            break;
        }
        // memset(pool->threadIDs, 0, sizeof(pthread_t) * max);
        for (int i = 0; i < max; i++)
            pool->threadIDs[i] = 0;

        pool->minNum = min;
        pool->maxNum = max;
        pool->busyNum = 0;
        pool->liveNum = min;
        pool->exitNum = 0;

        if (pthread_mutex_init(&pool->mutexPool, NULL) != 0 ||
            pthread_mutex_init(&pool->mutexBusy, NULL) != 0 ||
            pthread_cond_init(&pool->notEmpty, NULL) != 0 ||
            pthread_cond_init(&pool->notFull, NULL) != 0)
        {
            printf("mutex or cond init failed\n");
            break;
        }

        // 任务队列
        pool->taskQ = (Task *)malloc(sizeof(Task) * queueSize);
        if (pool->taskQ == NULL)
        {
            printf("malloc taskQ failed\n");
            break;
        }
        pool->queueCapacity = queueSize;
        pool->queueSize = 0;
        pool->queueFront = 0;
        pool->queueRear = 0;
        pool->shutdown = 0;

        if (pthread_create(&pool->managerID, NULL, manager, pool))
        {
            perror("create pthread_create managerID failed");
            break;
        }

        for (int i = 0; i < min; i++)
        {
            if (pthread_create(&pool->threadIDs[i], NULL, worker, pool))
            {
                perror("create pthread_create threadIDs failed");
                break;
            }
        }

        return pool;
    } while (0);

    // 初始化失败,释放资源
    if (pool && pool->threadIDs)
        free(pool->threadIDs);
    if (pool && pool->taskQ)
        free(pool->taskQ);
    if (pool)
        free(pool);
    return NULL;
}

// 线程池添加任务
void threadPoolAdd(ThreadPool *pool, void (*func)(void *), void *arg)
{
    pthread_mutex_lock(&pool->mutexPool);

    // 因为任务队列满了或者线程池需要销毁,阻塞生产者线程
    while (pool->queueSize == pool->queueCapacity && !pool->shutdown)
        pthread_cond_wait(&pool->notFull, &pool->mutexPool);

    if (pool->shutdown)
    {
        pthread_mutex_unlock(&pool->mutexPool);
        return;
    }

    // 添加任务
    pool->taskQ[pool->queueRear].function = func;
    pool->taskQ[pool->queueRear].arg = arg;
    pool->queueRear = (pool->queueRear + 1) % pool->queueCapacity;
    pool->queueSize++;

    pthread_mutex_unlock(&pool->mutexPool);
    pthread_cond_signal(&pool->notEmpty);
}

// 销毁线程池, 失败-1,成功0
int threadPoolDestroy(ThreadPool *pool)
{
    if (pool == NULL)
        return -1;

    // 关闭线程池
    pool->shutdown = -1;

    // 等待管理者线程结束
    pthread_join(pool->managerID, NULL);
    printf("manager thread quit!\n");

    // 唤醒阻塞的消费者线程(工作线程)
    for (int i = 0; i < pool->liveNum; i++)
        pthread_cond_signal(&pool->notEmpty);

    // 等待工作线程结束
    //pthread_mutex_lock(&pool->mutexPool);
    for (int i = 0; i < pool->maxNum; i++)
    {
        if (pool->threadIDs[i] != 0)
        {
            pthread_join(pool->threadIDs[i], NULL);
            pool->threadIDs[i] = 0;
            pool->liveNum--;
        }
    }
    //pthread_mutex_unlock(&pool->mutexPool);
    printf("work threads quit!\n");
    

    // 释放堆内存
    if (pool->taskQ)
        free(pool->taskQ);
    if (pool->threadIDs)
        free(pool->threadIDs);

    // 销毁互斥量,条件变量
    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->notEmpty);
    pthread_cond_destroy(&pool->notFull);

    free(pool);
    pool = NULL;

    return 0;
}

// 测试案例
void taskFunc(void *arg)
{
    int num = *(int *)arg;
    printf("taskFunc thread %ld is working, number = %d\n", pthread_self(), num);
    // sleep(3);
}

int main()
{
#define N 130
    ThreadPool *pool = threadPoolCreate(5, 15, 100);
    for (int i = 0; i < N; i++)
    {
        int *num = (int *)malloc(sizeof(int));
        *num = i + 100;
        threadPoolAdd(pool, taskFunc, num);
    }
    sleep(1);
    threadPoolDestroy(pool);

    printf("Over!\n");
    return 0;
}

C++线程池

3.40.cpp
#include 
#include 
#include 

#include 
#include 
using namespace std;

class CTask
{
public:
	CTask(void *ptrData = nullptr) : m_ptrData(ptrData) {}
	virtual ~CTask() {}

	virtual void Run() = 0;

protected:
	void *m_ptrData;
};

class CMyTask : public CTask
{
public:
	CMyTask(void *ptrData = nullptr) : CTask(ptrData) {}

	void Run()
	{
		printf("%s\n", (char *)m_ptrData);
		sleep(rand() % 4 + 1);
	}
};

class CThreadPool
{
private:
	static vector<CTask *> m_vecTaskList;
	static bool shutdown;
	static pthread_mutex_t m_pthreadMutex;
	static pthread_cond_t m_pthreadCond;

	int m_iThreadNum;
	pthread_t *pthread_id;

protected:
	static void *ThreadFunc(void *threadData);
	// static int MoveToIdle(pthread_t tid);
	// static int MoveToBusy(pthread_t tid);

	void Create()
	{
		pthread_id = new pthread_t[m_iThreadNum];
		for (int i = 0; i < m_iThreadNum; i++)
			pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
	}

public:
	static int getTaskSize();

	CThreadPool(int threadNum) : m_iThreadNum(threadNum)
	{
		printf("I will create %d threads.\n", threadNum);
		Create();
	}

	void AddTask(CTask *task)
	{
		pthread_mutex_lock(&m_pthreadMutex);
		m_vecTaskList.push_back(task);
		pthread_mutex_unlock(&m_pthreadMutex);

		pthread_cond_signal(&m_pthreadCond);
	}

	int StopAll()
	{
		if (shutdown)
			return -1;

		printf("Now I will end all threads!\n\n");

		pthread_mutex_lock(&m_pthreadMutex);
		shutdown = true;
		pthread_mutex_unlock(&m_pthreadMutex);

		pthread_cond_broadcast(&m_pthreadCond);

		for (int i = 0; i < m_iThreadNum; i++)
			pthread_join(pthread_id[i], NULL);

		delete[] pthread_id;
		pthread_id = NULL;

		//  pthread_mutex_destroy(&m_pthreadMutex);
		//  pthread_mutex_destroy(&m_pthreadCond);

		return 0;
	}
};

vector<CTask *> CThreadPool::m_vecTaskList;
bool CThreadPool::shutdown = false;
pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;

int CThreadPool::getTaskSize()
{
	return m_vecTaskList.size();
}

void *CThreadPool::ThreadFunc(void *threadData)
{
	pthread_t tid = pthread_self();
	while (true)
	{
		pthread_mutex_lock(&m_pthreadMutex);

		while (getTaskSize() == 0 && !shutdown)
			pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);

		if (shutdown)
		{
			pthread_mutex_unlock(&m_pthreadMutex);
			printf("[tid: %lu]\texit\n", tid);
			pthread_exit(NULL);
		}

		printf("[tid: %lu]\trun: ", tid);
		vector<CTask *>::iterator iter = m_vecTaskList.begin();
		CTask *task = *iter;
		m_vecTaskList.erase(iter);

		pthread_mutex_unlock(&m_pthreadMutex);

		task->Run();
		printf("[tid: %lu]\tidle\n", tid);
	}

	return (void *)0;
}

int main()
{
	if (true)
	{
		CThreadPool threadpool(5);
		string str[10];
		for (int i = 0; i < 10; i++)
		{
			str[i] = string("hello ") + to_string(i);
			threadpool.AddTask(new CMyTask((void *)(str[i].c_str())));
		}

		while (true)
		{
			printf("There are still %d tasks need to handle\n", CThreadPool::getTaskSize());

			if (CThreadPool::getTaskSize() == 0)
			{
				if (threadpool.StopAll() == -1)
				{
					printf("Thread pool clear, exit.\n");
					break;
				}
			}

			sleep(2);
			printf("2 seconds later...\n");
		}
	}
	return 0;
}

3.8.4 C++11线程池

3.41.cpp
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define testout(msg) cout << msg << endl

class XTask
{
public:
    virtual ~XTask() {}

    // 一客户端一个base
    // struct event_base *base = 0;

    // 线程池id
    // int thread_id = 0;

    // 初始化任务
    virtual void Init(int arg) = 0;
};

class CMyTask : public XTask
{
public:
    void Init(int arg)
    {
        for (long long c = 0; c < 10000000; c++)
            for (long long i = 0; i < 10000000; i++)
                ;

        printf("%d---------%d--------\n", arg, arg);
    }
};

class XThread
{
public:
    void Main()
    {
        cout << id << " thread::Main() begin" << endl;

        cout << id << " thread::Main() end" << endl;
    }

    void Start()
    {
        testout(id << " thread At Start()");

        thread th(&XThread::Main, this);
        th.detach();
    }

    void Activate(int arg)
    {
        testout(id << " thread At Activate()");

        mtx.lock();

        if (tasks.empty())
        {
            mtx.unlock();
            return;
        }

        XTask *t = tasks.front();
        tasks.pop_front();

        mtx.unlock();

        t->Init(arg);
    }

    void AddTask(XTask *t)
    {
        if (t)
        {
            // t->base = base;
            mtx.lock();
            tasks.push_back(t);
            mtx.unlock();
        }
    }

    // void Notify();
    int id = 0;

private:
    // event_base *base = 0;
    list<XTask *> tasks;
    mutex mtx;
};

class XThreadPool
{
public:
    void Init(int _threadCount)
    {
        testout("main thread At XThreadPoll::Init()");

        threadCount = _threadCount;
        lastThread = -1;
        for (int i = 0; i < threadCount; i++)
        {
            cout << "Create thread" << i << endl;
            XThread *t = new XThread();
            t->id = i;
            t->Start();
            threads.push_back(t);

            this_thread::sleep_for(chrono::milliseconds(10));
        }
    }

    void Dispatch(XTask *task, int arg)
    {
        testout("main thread At XThreadPoll::dispathch()");

        if (task)
        {
            int tid = (lastThread + 1) % threadCount;
            lastThread = tid;

            XThread *t = threads[tid];
            t->AddTask(task);
            t->Activate(arg);
        }
    }

private:
    int threadCount;
    int lastThread = -1;
    vector<XThread *> threads;
};

int main()
{
    {
#define N 10
        XThreadPool threadpool;
        threadpool.Init(N); // 初始化线程池

        CMyTask task[N];

        for (int i = 0; i < N; i++)
            threadpool.Dispatch(&task[i], i); // 分配任务
#undef N
    }

    return 0;
}
3.41_0.cpp
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

class XTask
{
public:
    virtual ~XTask() {}

    void setData(void *_data)
    {
        data = _data;
    }

    virtual void Run() = 0;

protected:
    void *data = NULL;
};

class CMyTask : public XTask
{
public:
    void Run()
    {
        int n = *(int *)data;
        cout << "Task " << n << " start" << endl;
        for (int c = 0; c < 1000; c++)
            for (int i = 0; i < 1000; i++)
                ;
        cout << "Task " << n << " end" << endl;
    }
};

class XThread
{
public:
    void Main()
    {
        thread::id id = this_thread::get_id();
        cout << "Thread " << id << " start" << endl;
        while (true)
        {
            XTask *t;
            {
                unique_lock<mutex> lk(mtx);
                while (tasks.empty() && !quit)
                    cv.wait(lk);

                if (quit)
                {
                    cout << "Thread " << id << " quit" << endl;
                    break;
                }
                t = tasks.front();
                tasks.pop_front();
            }
            t->Run();
        }
        cout << "Thread " << id << " end" << endl;
    }

    void AddTask(XTask *t)
    {
        mtx.lock();
        cout << "AddTask" << endl;
        tasks.push_back(t);
        cout << "TaskSize: " << tasks.size() << endl;
        mtx.unlock();

        cv.notify_one();
    }

    XThread()
    {
        quit = false;
        t = thread(&XThread::Main, this);
    }

    ~XThread()
    {
        mtx.lock();
        quit = true;
        mtx.unlock();

        cv.notify_one();

        t.join();
    }

private:
    bool quit;
    thread t;

    deque<XTask *> tasks;
    mutex mtx;
    condition_variable cv;
};

class XThreadPool
{
public:
    XThreadPool(int _threadCount = 10) : threadCount(_threadCount)
    {
        for (int i = 0; i < threadCount; i++)
        {
            threads.push_back(new XThread());
            // this_thread::sleep_for(chrono::milliseconds(10));
        }
        lastThread = -1;
    }
    ~XThreadPool()
    {
        for (int i = 0; i < threadCount; i++)
            delete threads[i];
    }

    void Dispatch(XTask *task)
    {
        lastThread = (lastThread + 1) % threadCount;
        threads[lastThread]->AddTask(task);
    }

private:
    int threadCount;
    int lastThread;
    vector<XThread *> threads;
};

int main()
{
    if (false)
    {
#define N 100
        CMyTask task[N];
        int data[N];
        XThread t;

        for (int i = 0; i < N; i++)
        {
            data[i] = i;
            task[i].setData((void *)&data[i]);
            t.AddTask(&task[i]);
        }
        sleep(1);
#undef N
    }

    if (true)
    {
#define N 100
        CMyTask task[N];
        int data[N];
        XThreadPool threadpool;

        for (int i = 0; i < N; i++)
        {
            data[i] = i;
            task[i].setData((void *)&data[i]);
            threadpool.Dispatch(&task[i]);
        }
        sleep(1);
#undef N
    }
    return 0;
}

你可能感兴趣的:(C/C++,整理,学习,linux,多线程,C/C++)