線程有點懵逼
線程之前函數回顧以及總結部分(對不清楚的問題再思考)
線程控制原語 進程控制原語
pthread_create(); fork();
pthread_self(); getpid();
pthread_exit(); exit();
pthread_join(); wait()/waitpid();
pthread_cancel(); kill();
pthread_detach();
這里寫一下昨天的join函數,那塊有點難理解。
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>struct thrd{int var ; char str[256];
};void* func(void * arg)
{struct thrd *th; // 這里不能直接使用結構體,因為這是在棧上的th = malloc(sizeof(struct thrd)); // 這邊需要在堆區分配內存,如果不使用堆區會發生錯誤,因為當線程執行完之后,棧上的內存會釋放,如果返回棧上的內容會非法訪問。th->val = 200;strcpy(th->str , "hello pthread_join");return (void*)th;
}int main(int argc , char* argv[])
{pthread_t tid ; struct thrd *retval;int ret = pthread_create(&tid , NULL , func , NULL);if(ret != 0){fprintf(stderr , "pthread_create error : %s\n" , strerror(ret)); exit(1); }ret = pthread_join(tid , (void**)&retval);if(ret != 0){fprintf(stderr , "pthread_join error : %s\n" , strerror(ret)); exit(1); }printf("child thread exit with var = %d , str = %s\n " , retval->val , retval->str);pthread_exit(NULL);}
線程當中用perror沒有用,線程會直接返回errno,所以在線程中錯誤一般使用下面這個格式:
if(ret != 0){fprintf(stderr , "pthread_create error : %s\n" , strerror(ret)); exit(1);
}
線程分離之后,子線程結束會自動回收,自動清理PCB,無需回收
ret = pthread_detach(tid)
線程屬性
初始化線程屬性
int pthread_attr_init(pthread_attr_t* attr);
成功返回0
失敗errnofprintf(stderr , "pthread_xxx error:%s\n" , strerror(ret));
銷毀線程屬性所占用的資源?
int pthread_attr_destroy(pthread_attr_t* attr);
成功返回0
失敗errno
fprintf(strerr , "pthread_attr_destroy error:%s\n" , strerror(ret));
設置線程分離
int pthread_attr_setdetachstate(pthread_attr_t* attr , int detachstate);參數:attr:已初始化的線程屬性
detachstate : PTHREAD_CREATE_DETACHED(分離線程)PTHRED_CREATE_JOINABLE(非分離線程)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>void* tfn(void* arg){printf("thread:pid = %d , tid = %lu\n" , getpid() , pthread_self());return NULL;
}int main(int argc , char *argv[])
{pthread_t tid ;//tid = pthread_self();pthread_attr_t attr;int ret = pthread_attr_init(&attr);if(ret != 0){fprintf(stderr , "pthread_attr_init error:%s/n" , strerror(ret));exit(1);}ret = pthread_attr_setdetachstate(&attr , PTHREAD_CREATE_DETACHED);//設置線>程屬性為分離屬性if(ret != 0){fprintf(stderr , "pthread_attr_setdetachstate error:%s/n" , strerror(ret));exit(1);}ret = pthread_create(&tid , &attr , tfn , NULL);if(ret != 0){fprintf(stderr , "pthread_create error:%s/n" , strerror(ret));exit(1);}ret = pthread_attr_destroy(&attr);if(ret != 0){fprintf(stderr , "pthread_attr_destory error:%s/n" , strerror(ret));exit(1);}ret = pthread_join(tid , NULL); // 如何查看是否是分離狀態,不使用那個函數,>函數太長了,可以使用join函數,如果join函數回收失敗出現錯誤,就表示已經為線程分離
。if(ret != 0){fprintf(stderr , "pthread_join error:%s/n" , strerror(ret));exit(1);}printf("main:pid = %d , tid = %lu\n" , getpid() , pthread_self());pthread_exit(NULL);
}
線程使用注意事項
1、主線程退出其他線程不退出,主線程要使用pthread_exit()。
2、避免僵尸線程。
3、malloc和mmap申請的內存可以被其他線程釋放。
4、避免在多線程模型中使用fork,子進程中只有調用fork的線程存在,其余均被退出。
5、信號的復雜語義很難和多線程共存,應避免在多線程引入信號機制。
線程同步
同步:協同,講究先后次序。
協同步調,對公共區域數據按序訪問,防止數據混亂,產生與時間有關的錯誤。
鎖的使用
建議鎖,對公共數據進行保護,所有進程應該在訪問公共數據之前先拿鎖再訪問,但鎖本身不具備強制性。
互斥鎖/互斥量mutex
?使用mutex(互斥量、互斥鎖)一般步驟
1、pthread_mutex_t lock;? ? 創建鎖
2、pthread_mutex_init(); 初始化鎖
3、pthread_mutex_lock(); 加鎖
4、訪問共享數據
5、pthread_mutex_unlock(); 解鎖
6、pthread_mutex_destory(); 銷毀鎖上述函數成功返回0,失敗返回errno
?注意事項:盡量保證鎖的粒度
restrict關鍵字:
用來限定指針變量,被該關鍵字限定的指針變量所指向的內存操作,必須由本指針完成int pthread_mutex_init(pthread_mutex_t *restrict mutex , const pthread_mutexattr_t *restrict attr);
今天沒學完,還要寫論文