C語(yǔ)言中的線程信號(hào)控制詳解
一、場(chǎng)景介紹
存在三個(gè)線程,一個(gè)主線程和兩個(gè)子線程(子線程數(shù)量不固定)。為了節(jié)省頻繁創(chuàng)建銷(xiāo)毀線程造成的資源浪費(fèi),將這些線程設(shè)置為常駐線程。但這樣引入了一個(gè)新的問(wèn)題,如何協(xié)調(diào)這些線程完成工作。
主線程內(nèi)是循環(huán)檢測(cè)某個(gè)文件夾內(nèi)文件的變動(dòng),當(dāng)文件夾內(nèi)出現(xiàn)新的文件時(shí),更新可拷貝文件列表,并告知子線程開(kāi)始干活;子線程拷貝結(jié)束后需要告知主線程任務(wù)完成了,主線程開(kāi)始下一輪檢測(cè)。

二、解決方法
1、臨時(shí)線程
主線程每次檢測(cè)完畢后,新建子線程執(zhí)行拷貝任務(wù),并阻塞等待線程任務(wù)的結(jié)束。
#include "main.h"
void *filecopy_thread(void *args)
{
pthread_t id = pthread_self();
PTHREAD_ARGS *thread_args = (PTHREAD_ARGS *)args;
string dst_dir = thread_args->dst_dir;
while (1)
{
// get the file to copy
pthread_mutex_lock(thread_args->mutex);
// exit when the list is empty
if (thread_args->file_list.empty())
{
pthread_mutex_unlock(thread_args->mutex);
break;
}
string src_file = thread_args->file_list.back();
thread_args->file_list.pop_back();
pthread_mutex_unlock(thread_args->mutex);
copy_file(src_file, dst_dir);
}
return NULL;
}
int main(int argc, char **argv)
{
while(1)
{
bool is_switch = oracle.is_redolog_switch();
// judge whether the redolog has bean switched
if ( is_switch )
{
printf("pthread create\n");
pthread_t *pthread_list = (pthread_t *)malloc(sizeof(pthread_t) * cfg_utils.m_filecopy_pcount);
if (!pthread_list)
{
LOG_F(ERROR, "pthread list created failed");
continue;
}
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
PTHREAD_ARGS pthread_args = {file_list_src, &mutex, cfg_utils.m_logbk_syspath, &oncebk_count};
struct timeval start, end;
gettimeofday(&start, NULL);
// start file copy thread
for (int i = 0; i < cfg_utils.m_filecopy_pcount; i++)
{
printf("creating pthread(%d)\n", i + 1);
pthread_create(pthread_list + i, NULL, filecopy_thread, &pthread_args);
}
// block until all file has copied
for (int i = 0; i < cfg_utils.m_filecopy_pcount; i++)
{
pthread_join(pthread_list[i], NULL);
}
gettimeofday(&end, NULL);
double timeuse = ( end.tv_sec - start.tv_sec ) + (end.tv_usec - start.tv_usec)/1000000.0;
printf("%.1lf(s)\n", timeuse);
pthread_mutex_destroy(&mutex);
free(pthread_list);
}
sleep(cfg_utils.m_bk_cycle);
}
return 0;
}
(1)優(yōu)點(diǎn)
邏輯簡(jiǎn)單
(2)缺點(diǎn)
頻繁創(chuàng)建與銷(xiāo)毀線程,資源浪費(fèi)。
2、全局變量信號(hào)
定義一個(gè)全局變量作為線程的控制信號(hào)。
主線程將該信號(hào)設(shè)置為子線程的個(gè)數(shù)的負(fù)數(shù),以啟動(dòng)子線程。
當(dāng)該信號(hào)小于 0 時(shí),子線程開(kāi)始啟動(dòng)。子線程的啟動(dòng)與任務(wù)完畢都需要將該信號(hào)加一。
當(dāng)主線程檢測(cè)到該信號(hào)為線程總數(shù)時(shí)推導(dǎo)子線程本次任務(wù)結(jié)束。

(1)優(yōu)點(diǎn)
子線程作為常駐線程,節(jié)省了一定的資源。
(2)缺點(diǎn)
子線程與主線程在等待信號(hào)的過(guò)程中要么造成 CPU 的空轉(zhuǎn),要么 sleep 會(huì)增加程序的處理時(shí)延。
而且,子線程啟動(dòng)與結(jié)束都對(duì)全局信號(hào)進(jìn)行加一的操作,極端情況(某些線程執(zhí)行速度存在極端差異)下可能造成信號(hào)控制的紊亂。
3、信號(hào)量
使用兩組信號(hào):start_signal 和 over_signal。
主線程啟動(dòng)子線程時(shí),需要將 start_signal 賦值為子線程數(shù),over_signal 賦值為0.
子線程執(zhí)行down(start_signal) ,該操作執(zhí)行成功即可執(zhí)行任務(wù)邏輯,執(zhí)行完后 up(over_signal)。
主線程需要執(zhí)行 num 次down(over_signal)操作,只有所有子線程執(zhí)行結(jié)束,該操作才可以執(zhí)行完成。
在等待執(zhí)行信號(hào)down和up的過(guò)程中,線程都是阻塞的,不會(huì)造成 CPU 的空轉(zhuǎn),當(dāng)信號(hào)可操作時(shí)也會(huì)立即執(zhí)行,不會(huì)增加操作時(shí)延。

到此這篇關(guān)于C語(yǔ)言中的線程信號(hào)控制詳解的文章就介紹到這了,更多相關(guān)C語(yǔ)言線程信號(hào)控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中std::invalid_argument報(bào)錯(cuò)解決
在C++編程中,std::invalid_argument是一個(gè)常見(jiàn)的異常,用于指示函數(shù)參數(shù)無(wú)效,文章詳細(xì)解析了這一異常的產(chǎn)生原因,并提供了多種解決策略,感興趣的可以了解一下2024-09-09
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)與算法之排序總結(jié)(二)
這篇文章住要介紹的是選擇類(lèi)排序中的簡(jiǎn)單、樹(shù)形和堆排序,歸并排序、分配類(lèi)排序的基數(shù)排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2021-12-12
C語(yǔ)言實(shí)現(xiàn)隨機(jī)搶紅包功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)隨機(jī)搶紅包功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
vscode搭建STM32開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程
這篇文章主要介紹了vscode搭建STM32開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
純c語(yǔ)言優(yōu)雅地實(shí)現(xiàn)矩陣運(yùn)算庫(kù)的方法
本文主要介紹了純c語(yǔ)言優(yōu)雅地實(shí)現(xiàn)矩陣運(yùn)算庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
Qt使用QChart實(shí)現(xiàn)動(dòng)態(tài)顯示溫度變化曲線
Qt的QChart是一個(gè)用于繪制圖表和可視化數(shù)據(jù)的類(lèi),提供了一個(gè)靈活的、可擴(kuò)展的、跨平臺(tái)的圖表繪制解決方案,所以本文就將使用QChart實(shí)現(xiàn)動(dòng)態(tài)顯示3個(gè)設(shè)備的溫度變化曲線,感興趣的可以了解一下2023-06-06
C++實(shí)現(xiàn)LeetCode(27.移除元素)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(27.移除元素),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07

