Linux 下創建線程
線程是CPU運行的最小的調度單位,一個進程裏面可以有多個併發的線程。但是至少有一個線程。在linux裏面真正的線程這個東西,有的至少輕量級的進程,linux裏面的線程和進程的創建其實都是fork()函數和exec() 函數對clone()函數不同的封裝實現的,他們通過傳入不同的參數實現了子進程和父進程在一些資源上共享權限,地址空間、文件系統、打開的文件、信號處理程序等,如果子進程和父進程沒有共享任何東西,那麼就是兩個獨立的進程,不然就是線程了。
在linux下面,可以通過函數 pthread_create()來創建進程,
第一個參數,用來接收是創建的線程ID
第二個參數,用來描述創建的線程的屬性,一般爲NULL,具體是啥可以去查資料
第三參數,是線程的入口函數,是一個void *指針
第四個參數,是出入線程的參數,也是一個指針
//參數
int pthread_create( pthread_t *restict thread,
const pthread_attr_t *restric attr,
void *( *start_routine )( void* ),
void *restrict arg );
//創建新的線程的方法
error = pthread_create( &tid, NULL, ( void* )thread, NULL );
if( error )
{
printf("thread can not create!\n");
return -1;
}
我們一般用一個數據去接收創建線程函數的返回值,如果返回的是0表明創建線程成功了,如果不是,就說明有問題。返回的是錯誤碼。在線程裏面我們可以用pthread_self()函數去獲取當前線程的ID,對應於進程裏面的getpid(),可以參考文獻:
可以通過pthread_join()來阻塞的等待線程退出,下面給了一個例子。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// This is the first thread
void * pthread_1()
{
int num=1000;
while(num>=0)
{
printf("This the first thread, output is %d\n",num);
num--;
sleep(1);
}
}
// This is the second thread
void * pthread_2()
{
int num=0;
while(num<=1000)
{
printf("This the second thread, output is %d\n",num);
num++;
sleep(1);
}
}
int main()
{
pthread_t tips_1;
pthread_t tips_2;
if(pthread_create(&tips_1,NULL,pthread_1,NULL)!=0)
{
printf("thread 1 failed");
exit(0);
}
if(pthread_create(&tips_2,NULL,pthread_2,NULL)!=0)
{
printf("thread 2 failed");
exit(0);
}
//wati for the thread end
void * result1;
void * result2;
pthread_join(tips_1,&result1);
pthread_join(tips_2,&result2);
return 0;
}
Window下創建線程
window下創建線程可以通過 CreateThread()函數來創建,這個函數是Windows提供API函數來創建線程,但是其實還有一個C/C++的創建線程的函數_beginthreadex()。一把大劍都推薦使用後面這個_beginthreadex()函數,爲啥勒,因爲一開始的時候,其實C語言是不支持多線程的,標準的C運行庫在1970年被實現,當時沒有人考慮多線程的操作,所有很多寫標準C運行庫的程序員會使用全局變量errno,很多運行庫出錯了之後,都會去修改這個全局變量,所以這裏面就有問題了,如果一個線程在使用errno,這個時候另外一個線程啓動了,並且出了錯誤,將錯誤的碼更新了,那麼這個時候原理的線程就會出錯,因爲errno被修改了。
爲了搞定這個問題,Windows讓每個線程都有自己的一塊內存用來存放標準的C運行庫的函數,這個內存的創建就是用_beginthreadex()來創建的,所以,很多人會推薦使用這個函數,因爲會安全一點點。可以看看文獻2
這裏介紹一下CreatThead()函數
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
);
第一參數表示線程的內核對象的安全屬性
第二個參數表示線程棧空間的大小傳入0表示默認大小 1Mb
第三個參數 表示線程的起始地址,
第四個參數表示線程的傳入參數
第五個參數表示額外的控制線程創建,傳入0表示創建後馬上進行調度 如果爲CREATE_SUSPENDED則表示線程創建後暫停運行,這樣它就無法調度,直到調用ResumeThread()。
第六個參數 將會返回線程的ID,傳入NULL 表示不需要返回ID好。
返回參數:創建成功之後會返回新的線程的句柄,失敗返回NULL,HANDLE 是一個 void *指針
WINAPI 表示的是 __stdcall 一種函數的調用方式
DWORD 表示寬字節,好像是unsigned long 形數據
LPVOID 表示的是 void *指針
// CreatTheadTest.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
DWORD WINAPI ThreadFuncTest_1(LPVOID);
DWORD WINAPI ThreadFuncTest_2(LPVOID);
int main()
{
HANDLE hThread[2];
DWORD threadId[2];
hThread[0] = CreateThread(NULL,0, ThreadFuncTest_1,0,0,&threadId[0]);
hThread[1] = CreateThread(NULL, 0, ThreadFuncTest_2, 0, 0,&threadId[1]);
cout << "我是主線程:" << GetCurrentThreadId() << endl;
//DWORD StatuCode = WaitForSingleObject(hThread, 500); //等待5s
//if (StatuCode == WAIT_OBJECT_0)
//{
// cout << "子線程結束" << endl;
//}
//else if (StatuCode == WAIT_TIMEOUT)
//{
// cout << "等待超時" << endl;
//}
DWORD StatuCode = WaitForMultipleObjects(2, hThread, true ,5000); //等待0.5s false 只要有一個線程返回就返回 true 要等所有的線程返回
if (StatuCode == WAIT_OBJECT_0)
{
cout << "子線程結束" << endl;
}
else if (StatuCode == WAIT_TIMEOUT)
{
cout << "等待超時" << endl;
}
Sleep(2000);
system("pause");
return 0;
}
DWORD WINAPI ThreadFuncTest_1(LPVOID)
{
cout << "我是子線程,ID:" << GetCurrentThreadId() << endl;
unsigned int count = 0;
while (count<20)
{
cout << "本線程爲:" << GetCurrentThreadId() << "輸出爲:" << count << endl;
Sleep(1);
count++;
}
return 0;
}
DWORD WINAPI ThreadFuncTest_2(LPVOID)
{
cout << "我是子線程,ID:" << GetCurrentThreadId() << endl;
unsigned int count = 20;
while (count>0)
{
cout << "本線程爲:" << GetCurrentThreadId() << "輸出爲:" << count << endl;
Sleep(1);
count--;
}
return 0;
}
WaitForMultipleObjects()等待多個線程返回
WaitForSingleObject 等待單個線程的返回
參考文獻:
文獻 1:https://blog.csdn.net/qq_22847457/article/details/89371217
文獻 2:https://blog.csdn.net/zhanghuan_wangkai/article/details/52045900