1. 线程的概念
线程是程序执行流的最小单元,也称为轻量级进程。2. 进程的概念
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础3. 线程与进程的关系
一个进程至少有一个线程,一个线程只属于一个进程。进程是系统进行资源分配和调度的一个单位,线程是进程的一个实体,线程除了拥有再运行中必不可少的资源(如程序计数器,一组寄存器和栈)不拥有任何系统资源,只能使用所属进程的资源
4. windows环境多线程
4.1 windows创建线程API
HANDLE WINAPI CreateThread(
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in_opt LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out_opt LPDWORD lpThreadId
);
- lpThreadAttributes
指向LPSECURITY_ATTRIBUTES结构体的指针,默认设为NULL,让线程使用默认的安全性。如果希望所有子线程能够继承线程对象的句柄,则必须设定LPSECURITY_ATTRIBUTES结构体,将它的bInHeriHandle初始化未TRUE。
- dwStackSize
设置初始栈的大小,默认设为0。
- lpStartAddress
指向LPTHREAD_START_ROUTINE指向的函数指针,即为新线程的起始地址。该函数的名称任意,但是函数类型必须遵照下面声明的形式:
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
LPVOID lpThreadParameter
);
- lpParameter
新线程调用函数的命令行参数。
- dwCreationFlags
用于控制线程创建的附加标记。可以使两个值之一:CRETE_SUSPENDED或0。如果是SUSPENDED,那么线程创建后将处于暂停状态。如果是0,线程在创建后立即运行。
- lpThreadId
指向一个变量,用来接受线程的ID。如果对线程ID不感兴趣可以直接设为NULL。
注意:CreateThread()函数传回的值有两个,第一个值是返回值HANDLE,这个值是线程的HANDLE,是线程所在的进程中的局部变量,在不同的进程中是不唯一的,所以你不能直接跨进程的把一个线程的HANDLE传给另外一个进程中的线程让其使用。第二个值是由lpThreadId传回的线程ID,此值是一个全局变量,可以独一无二的表示系统中任意进程中的某个线程。比如调用AttachThreadInput()或PostThreadMessage()就需要用线程ID,而不能用线程的HANDLE。
4.2 等待函数
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。
DWORD WaitForSingleObject(
HANDLE hObject,
DWORD dwMilliseconds
);
- hObject
标识一个能够支持被通知/未通知的内核对象(前面列出的任何一种对象都适用)。
- dwMilliseconds
允许该线程指明,为了等待该对象变为已通知状态,它将等待多长时间。(INFINITE为无限时间量,INFINITE已经定义为0xFFFFFFFF(或-1))
4.3 windows实例
/
//\
//\ windwos多线程练习
//\ 2017-05-26 cwp
//\
/
#include <stdio.h>
#include <windows.h>
// 线程函数
DWORD WINAPI ThreadFunc(LPVOID arg)
{
printf("thread id:%d, ThreadFunc\n", GetCurrentThreadId());
return NULL;
}
int main()
{
printf("thread id:%d, man\n", GetCurrentThreadId());
HANDLE handle = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
printf("Thread id:%d, Wait ThreadFunc exit\n", GetCurrentThreadId());
WaitForSingleObject(handle, INFINITE);
CloseHandle(handle);
return 0;
}
4.4运行结果
5. linux多线程
Linux系统内核只提供了轻量级进程的支持,并未实现线程模型。我们常用的LinuxThreads只是一个伪线程,是在用户级实现一个包括信号处理在内的线程管理机制。
5.1 线程创建函数pthread_create
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
参数说明:
- thread:指向pthread_create类型的指针,用于引用新创建的线程。
- attr:用于设置线程的属性,一般不需要特殊的属性,所以可以简单地设置为NULL。
- start_routine:传递新线程所要执行的函数地址。
- arg:新线程所要执行的函数的参数。
返回值:
调用如果成功,则返回值是0;如果失败则返回错误代码。
每个线程都有自己的线程ID,以便在进程内区分。线程ID在pthread_create调用时回返给创建线程的调用者;一个线程也可以在创建后使用pthread_self()调用获取自己的线程ID.
5.2 线程等待函数pthread_join
int pthread_join(pthread_t thread, void **retval);
参数说明:
- thread:pthread_create类型的指针,等待该线程运行结束。
- retval:线程的返回值。
返回值:
调用如果成功,则返回值是0;如果失败则返回错误代码。
5.3 示例代码
/
//\
//\ linux多线程示例
//\ 2017-05-25 cwp
//\
/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#define gettid() syscall(__NR_gettid)
// 线程1
void *ThreadFunc1(void *arg)
{
printf("Process id :%lu, Thread id : %lu, ThreadFunc1\n", getpid(), gettid());
return NULL;
}
// 线程2
void *ThreadFunc2(void *arg)
{
printf("Process id :%lu, Thread id : %lu, ThreadFunc2\n", getpid(), gettid());
char *tmp = new char[strlen("ThreadFunc2") + 1];
memset(tmp, 0, 10);
sprintf(tmp, "ThreadFunc2");
return (void *)tmp;
}
int main()
{
pthread_t id[2];
// 创建线程1
int ret = pthread_create(&id[0], NULL, ThreadFunc1, NULL);
if (ret != 0)
{
printf("Create thread1 failed!\n");
return 0;
}
// 创建线程2
ret = pthread_create(&id[1], NULL, ThreadFunc2, NULL);
if (ret != 0)
{
printf("Create thread2 failed!\n");
return 0;
}
// 等待线程1退出
pthread_join(id[0], NULL);
// 等待线程2退出,并打印线程2的返回值
void *value = NULL;
pthread_join(id[1], &value);
printf("Process id :%lu, Thread id : %lu, man value : %s\n", getpid(), gettid(), (char *)value);
delete [] (char *)value;
return 0;
}
注:该博文同时更新博客园(风逝_陈) http://www.cnblogs.com/wpchen/p/6911078.html