線程,有時被稱爲輕量進程,是程序執行的最小單元。
C++11線程
#include <thread>
void task(int i) {
cout << "task:" << i << endl;
}
thread t1(task,100);
//等待線程結束再繼續執行
t1.join();
POSIX線程
POSIX 可移植操作系統接口,標準定義了操作系統應該爲應用程序提供的接口標準
Windows上使用 配置: 下載
cmake_minimum_required (VERSION 3.8)
include_directories("XXX/pthreads-w32-2-9-1-release/Pre-built.2/include")
#設置變量爲x64 or x86
if(CMAKE_CL_64)
set(platform x64)
else()
set(platform x86)
endif()
link_directories("XXX/pthreads-w32-2-9-1-release/Pre-built.2/lib/${platform}")
#如果出現 “timespec”:“struct” 類型重定義 設置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_STRUCT_TIMESPEC")
# 將源添加到此項目的可執行文件。
add_executable (lsn6example "lsn6_example.cpp" "lsn6_example.h")
target_link_libraries(lsn6example pthreadVC2)
32位拷貝pthreadVC2.dll 到windows/syswow64目錄
64位拷貝pthreadVC2.dll 到windows/system32目錄
#include <pthread.h>
void *pthreadTask(void* args) {
int* i = static_cast<int*>(args);
cout << "posix線程:" << *i << endl;
return 0;
}
pthread_t pid;
int pi = 100;
pthread_create(&pid, 0, pthreadTask, &pi);
//等待線程的結束
pthread_join(pid,0);
線程屬性
線程具有屬性,用 pthread_attr_t 表示
pthread_attr_t attr;
//初始化 attr中爲操作系統實現支持的線程所有屬性的默認值
pthread_attr_init(&attr);
pthread_attr_destroy(&attr);
分離線程
線程創建默認是非分離的,當pthread_join()函數返回時,創建的線程終止,釋放自己佔用的系統資源
分離線程不能被其他線程等待,pthread_join無效,線程自己玩自己的。
//設置是否爲分離線程
//PTHREAD_CREATE_DETACHED 分離
//PTHREAD_CREATE_JOINABLE 非分離
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
調度策略與優先級
Windows 無法設置成功
//設置調度策略
//返回0 設置成功
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
// SCHED_FIFO
// 實時調度策略,先到先服務 一旦佔用cpu則一直運行。一直運行直到有更高優先級任務到達或自己放棄。
// SCHED_RR
// 實時調度策略,時間輪轉 系統分配一個時間段,在時間段內執行本線程
//設置優先級
//獲得對應策略的最小、最大優先級
int max = sched_get_priority_max(SCHED_FIFO);
int min = sched_get_priority_min(SCHED_FIFO);
sched_param param;
param.sched_priority = max;
pthread_attr_setschedparam(&attr, ¶m);
線程同步
多線程同時讀寫同一份共享資源的時候,可能會引起衝突。需要引入線程“同步”機制,即各位線程之間有序地對共享資源進行操作。
#include <pthread.h>
using namespace std;
queue<int> q;
void *pop(void* args) {
//線程未同步導致的多線程安全問題
// 會有重複的數據取出並出現異常
if (!q.empty())
{
printf("取出數據:%d\n", q.front());
q.pop();
}
else {
printf("無數據\n");
}
return 0;
}
int main()
{
for (size_t i = 0; i < 5; i++)
{
q.push(i);
}
pthread_t pid[10];
for (size_t i = 0; i < 10; i++)
{
pthread_create(&pid[i], 0, pop, &q);
}
system("pause");
return 0;
}
加入互斥鎖
queue<int> q;
pthread_mutex_t mutex;
void *pop(void* args) {
// 鎖
pthread_mutex_lock(&mutex);
if (!q.empty())
{
printf("取出數據:%d\n", q.front());
q.pop();
}
else {
printf("無數據\n");
}
// 放
pthread_mutex_unlock(&mutex);
return 0;
}
int main()
{
//初始化互斥鎖
pthread_mutex_init(&mutex, 0);
for (size_t i = 0; i < 5; i++)
{
q.push(i);
}
pthread_t pid[10];
for (size_t i = 0; i < 10; i++)
{
pthread_create(&pid[i], 0, pop, &q);
}
//需要釋放
for (size_t i = 0; i < 10; i++)
{
pthread_join(pid[i], 0);
}
pthread_mutex_destroy(&mutex);
system("pause");
return 0;
}
條件變量
條件變量是線程間進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立",從而喚醒掛起線程
```cpp
template <class T>
class SafeQueue {
public:
SafeQueue() {
pthread_mutex_init(&mutex,0);
}
~SafeQueue() {
pthread_mutex_destory(&mutex);
}
void enqueue(T t) {
pthread_mutex_lock(&mutex);
q.push(t);
pthread_mutex_unlock(&mutex);
}
int dequeue(T& t) {
pthread_mutex_lock(&mutex);
if (!q.empty())
{
t = q.front();
q.pop();
pthread_mutex_unlock(&mutex);
return 1;
}
pthread_mutex_unlock(&mutex);
return 0;
}
private:
queue<T> q;
pthread_mutex_t mutex;
};
> 上面的模板類存放數據T,並使用互斥鎖保證對queue的操作是線程安全的。這就是一個生產/消費模式。
> 如果在取出數據的時候,queue爲空,則一直等待,直到下一次enqueue加入數據。
> 這就是一個典型的生產/消費模式, 加入條件變量使 “dequeue” 掛起,直到由其他地方喚醒
```cpp
#pragma once
#include <queue>
using namespace std;
template <class T>
class SafeQueue {
public:
SafeQueue() {
pthread_mutex_init(&mutex,0);
pthread_cond_init(&cond, 0);
}
~SafeQueue() {
pthread_mutex_destory(&mutex);
pthread_cond_destory(&cond);
}
void enqueue(T t) {
pthread_mutex_lock(&mutex);
q.push(t);
//發出信號 通知掛起線程
//由系統喚醒一個線程
//pthread_cond_signal(&cond);
// 廣播 對應多個消費者的時候 多個線程等待喚醒所有
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
int dequeue(T& t) {
pthread_mutex_lock(&mutex);
//可能被意外喚醒 所以while循環
while (q.empty())
{
pthread_cond_wait(&cond, &mutex);
}
t = q.front();
q.pop();
pthread_mutex_unlock(&mutex);
return 1;
}
private:
queue<T> q;
pthread_mutex_t mutex;
pthread_cond_t cond;
};
#include "lsn6_example.h"
#include <thread>
#include <pthread.h>
using namespace std;
#include "safe_queue.h"
SafeQueue<int> q;
void *get(void* args) {
while (1) {
int i;
q.dequeue(i);
cout << "消費:"<< i << endl;
}
return 0;
}
void *put(void* args) {
while (1)
{
int i;
cin >> i;
q.enqueue(i);
}
return 0;
}
int main()
{
pthread_t pid1, pid2;
pthread_create(&pid1, 0, get, &q);
pthread_create(&pid2, 0, put, &q);
pthread_join(pid2,0);
system("pause");
return 0;
}