安裝man文檔
sudo apt-get install glibc-doc
sudo apt-get install manpages-posix-dev
ps -Lf pid
,查看指定線程的LWP號。pthread_t pthread_self(void);
?- 返回值:成功:0;失敗:無!int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h> void *thread_func(void *arg)
{printf("In thread: thread id = %lu, pid = %u\n", pthread_self(), getpid());return NULL;
}int main()
{pthread_t tid;int ret;printf("In main1: thread id = %lu, pid = %u\n", pthread_self(), getpid());ret = pthread_create(&tid, NULL, thread_func, NULL);if(ret != 0){fprintf(stderr, "pthread_create error:%s\n", strerror(ret));exit(1);} sleep(1);printf("In main2: thread id = %lu, pid = %u\n", pthread_self(), getpid());return 0;
}
(void *)&i
,將線程主函數內改為i = *((int *)arg)
是否可以?不可以。示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void *thread_func(void *arg)
{int i = (int)arg;sleep(i);printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid());return NULL;
}int main()
{pthread_t tid;int ret, i;for (i = 0; i<5; i++){ret = pthread_create(&tid, NULL, thread_func, (void *)i);if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret));exit(1); } } sleep(i);return 0;
}
【練習】:設計程序,驗證線程之間共享全局數據。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>int var = 100;void *tfn(void *arg)
{var = 200;printf("thread\n");return NULL;
}int main(void)
{printf("At first var = %d\n", var);pthread_t tid;pthread_create(&tid, NULL, tfn, NULL);sleep(1);printf("After pthread_create, var = %d\n", var); return 0;
}
示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void *thread_func(void *arg)
{int i = (int)arg;printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid());return NULL;
}int main()
{pthread_t tid;int ret, i;for (i = 0; i<5; i++){ret = pthread_create(&tid, NULL, thread_func, (void *)i);if(ret != 0){fprintf(stderr, "pthread_create error:%s\n", strerror(ret));exit(1);}} pthread_exit(NULL);
}
int pthread_join(pthread_t thread, void **retval);
?成功:0;失敗:錯誤號。【練習】:參數retval非空用法。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>typedef struct{int a;int b;
} exit_t;void *tfn(void *arg)
{exit_t * ret;ret = malloc(sizeof(exit_t));ret->a = 100;ret->b = 300;pthread_exit((void *)ret);
}int main(void)
{pthread_t tid;exit_t * retval;pthread_create(&tid, NULL, tfn, NULL);//調用pthread_join可以獲取線程的退出狀態pthread_join(tid, (void **)&retval);printf("a = %d, b = %d\n", retval->a, retval->b);free(retval);return 0;
}
【練習】:使用pthread_join函數將循環創建的多個子線程回收。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>int var = 100;void * tfn(void * arg)
{int i;i = (int)arg;sleep(i);if(i == 1){ var = 333;printf("var = %d\n", var);return var;} else if (i == 3){ var = 777;printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var);pthread_exit((void *)var);} else {printf("I'm %dth pthread, pthread_id = %lu\n var = %d\n", i+1, pthread_self(), var);pthread_exit((void *)var);} return NULL;
}int main(void)
{pthread_t tid[5];int i;int *ret[5];for(i = 0; i < 5; i++)pthread_create(&tid[i], NULL, tfn, (void *)i);for(i = 0; i < 5; i++){pthread_join(tid[i], (void **)&ret[i]);printf("-------%d 's ret = %d\n'", i, (int)ret[i]);}printf("I'm main pthread tid = %lu\t var = %d\n", pthread_self(), var);sleep(i);return 0;
}
int pthread_detach(pthread_t thread);
,成功:0;失敗:錯誤號。一般情況下,線程終止后,其終止狀態一直保留到其它線程調用pthread_join獲取它的狀態為止。但是線程也可以被置為detach狀態,這樣的線程一旦終止就立刻回收它占用的所有資源,而不保留終止狀態。不能對一個已經處于detach狀態的線程調用pthread_join,這樣的調用將返回EINVAL錯誤。也就是說,如果已經對一個線程調用了pthread_detach就不能再調用pthread_join了。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>void *tfn(void *arg)
{int n = 3;while(n--){printf("thread count %d\n", n); sleep(1);} return (void *)1;
}int main(void)
{pthread_t tid;void *tret;int err;#if 0 //通過線程屬性來設置游離態pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_create(&tid, &attr, tfn, NULL);
#elsepthread_create(&tid, NULL, tfn, NULL);//讓線程分離-----自動退出,無系統殘留資源pthread_detach(tid);
#endifwhile(1){err = pthread_join(tid, &tret);printf("------------err = %d\n", err);if(err != 0)fprintf(stderr, "thread_join error : %s\n", strerror(err));elsefprintf(stderr, "thread exit code %d\n", (int)tret);}
}
int pthread_cancel(pthread_t thread);
,成功:0;失敗:錯誤號。#define PTHREAD_CANCELED((void *)-1)
。因此當我們對一個已經被取消的線程使用pthread_join回收時,得到的返回值為-1。【練習】:終止線程的三種方法。注意“取消點”的概念。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>void *tfn1(void *arg)
{printf("thread 1 returning\n");return (void *)111;
}void *tfn2(void *arg)
{printf("thread 2 exiting\n");pthread_exit((void *)222);
}void *tfn3(void *arg)
{while(1){//printf("thread 3: I'm going to die in 3 seconds ... \n");//sleep(1);pthread_testcancel(); //自己添加取消點} return (void *)666;
}int main()
{pthread_t tid;void *tret = NULL;pthread_create(&tid, NULL, tfn1, NULL);pthread_join(tid, &tret);printf("thread 1 exit code = %d\n\n", (int)tret);pthread_create(&tid, NULL, tfn2, NULL);pthread_join(tid, &tret);printf("thread 2 exit code = %d\n\n", (int)tret);pthread_create(&tid, NULL, tfn3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, &tret);printf("thread 3 exit code = %d\n", (int)tret);
}
int pthread_equal(pthread_t t1, pthread_t t2);
進程 線程fork pthread_create 創建exit pthread_exit 退出wait pthread_join 等待kill pthread_cancel 殺死getpid pthread_self 取得IDpthread_detach 分離
本節作為指引性介紹,Linux下線程的屬性是可以根據實際項目需要進行設置,之前我們討論的線程都是采用線程的默認屬性,默認屬性已經可以解決絕大多數開發時遇到的問題。如我們對程序的性能提出更高的要求,那么需要設置線程屬性,比如可以通過設置線程棧的大小來降低內存的使用,增加最大線程個數。
typedef struct{
int etachstate; //線程的分離狀態
int schedpolicy; //線程調度策略
struct sched_param schedparam; //線程的調度參數
int inheritsched; //線程的繼承性
int scope; //線程的作用域
size_t guardsize; //線程棧末尾的警戒緩沖區大小
int stackaddr_set; //線程的棧設置
void* stackaddr; //線程的位置
size_t stacksize; //線程的大小
} pthread_attr_t;
線程屬性主要包括如下屬性:作用域(scope)、棧尺寸(stack size)、棧地址(stack address)、優先級(priority)、分離的狀態(detached state)、調度策略和參數(scheduling policy and parameters)。默認的屬性為非綁定、非分離、缺省的堆棧、與父進程同樣級別的優先級。
int pthread_attr_init(pthread_attr_t *attr);
,成功:0; 失敗:錯誤號。int pthread_attr_destroy(pthread_attr_t *attr);
,成功:0;失敗:錯誤號。int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
這里要注意的一點是,如果設置一個線程為分離線程,而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了,它終止以后就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被創建的線程里調用pthread_cond_timedwait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程里常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,并不能解決同步的問題。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void *thread_func(void *arg)
{pthread_exit((void *)11);
}int main()
{pthread_t tid;int ret;pthread_attr_t attr;ret = pthread_attr_init(&attr);if(ret != 0){ fprintf(stderr, "pthread_attr_init error:%s\n", strerror(ret));exit(1);} pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);ret = pthread_create(&tid, &attr, thread_func, NULL);if(ret != 0){ fprintf(stderr, "pthread_create error:%s\n", strerror(ret));exit(1);} ret = pthread_join(tid, NULL);if(ret != 0){ fprintf(stderr, "pthread_join error:%s\n", strerror(ret));exit(1);} pthread_exit((void *)1); return 0;
}
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>#define SIZE 0X10000void *th_fun(void *arg)
{while(1)sleep(1);
}int main()
{pthread_t tid;int err, detachstate, i = 1;pthread_attr_t attr;size_t stacksize;void *stackaddr;pthread_attr_init(&attr);pthread_attr_getstack(&attr, &stackaddr, &stacksize);pthread_attr_getdetachstate(&attr, &detachstate);//默認是分離態if(detachstate == PTHREAD_CREATE_DETACHED)printf("thread detached\n");//默認是非分離else if (detachstate == PTHREAD_CREATE_JOINABLE)printf("thread join\n");elseprintf("thread un known\n");//設置線程分離屬性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);while(1){//在堆上申請內存,指定線程棧的起始地址和大小stackaddr = malloc(SIZE);if(stackaddr == NULL){perror("malloc");exit(1);}stacksize = SIZE;//借助線程的屬性,修改線程棧空間大小pthread_attr_setstack(&attr, stackaddr, stacksize);err = pthread_create(&tid, &attr, th_fun, NULL);if(err != 0){printf("%s\n", strerror(err));exit(1);}printf("%d\n", i++);}pthread_attr_destroy(&attr);
}
而,編程中、通信中所說的同步與生活中大家印象中的同步概念略有差異。“同”字應是指協同、協助、互相配合。主旨在協同步調,按預定的先后次序運行。
因此,所有“多個控制流,共同操作一個共享資源”的情況,都需要同步。
所有只能從第三點著手解決。使多個線程在訪問共享資源的時候,出現互斥。
因此,即使有了mutex,如果有線程不按規則來訪問數據,依然會造成數據混亂。
int pthread_mutex_init(pthread_mutex_t * restrict mutex, const pthread_mutexattr_t * restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&mutex, NULL);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
trylock加鎖失敗直接返回錯誤號(如:EBUSY),不阻塞。
看如下程序:該程序是非常典型的,由于共享、競爭而沒有加任何同步機制,導致產生于時間有關的錯誤,造成數據混亂。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void *tfn(void *arg)
{srand(time(NULL));while(1){printf("hello "); //模擬長時間操作共享資源,導致CPU易主,產生與時間有關的錯誤sleep(rand() % 3); printf("world\n");sleep(rand() % 3); }return NULL;
}int main(void)
{pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while(1){printf("HELLO "); sleep(rand() % 3); printf("WORLD\n");sleep(rand() % 3); }return 0;
}
5、main中加pthread_cancel()將子線程取消。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>//定義鎖
pthread_mutex_t mutex;void *tfn(void *arg)
{srand(time(NULL));while(1){//加鎖pthread_mutex_lock(&mutex);printf("hello "); //模擬長時間操作共享資源,導致CPU易主,產生與時間有關的錯誤sleep(rand() % 3); printf("world\n");//解鎖pthread_mutex_unlock(&mutex);sleep(rand() % 3); //添加檢查點pthread_testcancel();}return NULL;
}int main(void)
{int flag = 5;pthread_t tid;srand(time(NULL));//鎖初始化pthread_mutex_init(&mutex, NULL); //mutex = 1pthread_create(&tid, NULL, tfn, NULL);while(flag--){//加鎖pthread_mutex_lock(&mutex);printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");//解鎖pthread_mutex_unlock(&mutex);sleep(rand() % 3);}//取消子線程pthread_cancel(tid);pthread_join(tid, NULL);//鎖銷毀pthread_mutex_destroy(&mutex);return 0;
}
結論:在訪問共享資源前加鎖,訪問結束后立即解鎖。鎖的“粒度”應越小越好。
示例
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>int counter;
pthread_rwlock_t rwlock;void *th_write(void *arg)
{int t;int i = (int)arg;while(1){t = counter;usleep(1000);pthread_rwlock_wrlock(&rwlock); printf("======write %d: %lu: counter=%d ++counter=%d\n", i, pthread_self(), t, ++counter);pthread_rwlock_unlock(&rwlock);usleep(5000);} return NULL;
}void *th_read(void *arg)
{int i = (int)arg;while(1){pthread_rwlock_rdlock(&rwlock);printf("======read %d: %lu: %d\n", i, pthread_self(), counter);pthread_rwlock_unlock(&rwlock);usleep(900);} return NULL;
}//3個線程不定時寫全局資源,5個線程不定時讀同一全局資源
int main()
{int i;pthread_t tid[8];//初始讀寫鎖pthread_rwlock_init(&rwlock, NULL);for(i = 0; i < 3; i++)pthread_create(&tid[i], NULL, th_write, (void *)i);for(i = 0; i < 5; i++)pthread_create(&tid[i+3], NULL, th_read, (void *)i);for(i = 0; i < 8; i++)pthread_join(tid[i], NULL);//釋放讀寫鎖pthread_rwlock_destroy(&rwlock);return 0;
}
int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZED;
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex);
int pthread_cond_timedwait(pthread_cond_t * restrict cond, pthread_mutex_t * restrict mutex, const struct timespec * restrict abstime);
參3:參看man sem_timedwait
函數,查看struct timespec結構體。
struct timespec{time_t tv_sec; /*seconds*/ 秒long tv_nsec; /*nanoseconds*/ 納秒
};
如:time(NULL)返回的就是絕對時間。而alarm(1)是相對時間,相對當前時間定時1秒鐘。
struct timespec t = {1,0};
pthread_cond_timedwait(&cond, &mutex, &t);
只能定時到1970年1月1日 00:00:01秒(早已經過去)
在講解setitimer函數時我們還提到另一種時間類型
struct timeval{time_t tv_sec; /*seconds*/ 秒suseconds_t tv_usec; /*microseconds*/ 微秒
};
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
看如下示例,使用條件變量模擬生產者、消費者問題:
/*借助條件變量模擬,生產者-消費者問題*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>/*鏈表作為共享數據,需被互斥量保護*/
struct msg {struct msg *next;int num;
};struct msg *head;
struct msg *mp;/*靜態初始化一個條件變量和一個互斥量*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *consumer(void *p)
{for(;;){pthread_mutex_lock(&lock);while(head == NULL){ //頭指針為空,說明沒有節點pthread_cond_wait(&has_product, &lock);}mp = head;head = mp->next; //模擬消費掉一個產品pthread_mutex_unlock(&lock);printf("-Consume ---%d\n", mp->num);free(mp);sleep(rand() % 5);}
}void *producer(void *p)
{for(;;){mp = malloc(sizeof(struct msg));//模擬生產一個產品mp->num = rand() % 1000 + 1;printf("-Produce ---%d\n", mp->num);pthread_mutex_lock(&lock);mp->next = head;head = mp;pthread_mutex_unlock(&lock);//將等待在該條件變量上的一個線程喚醒pthread_cond_signal(&has_product);sleep(rand() % 5);}
}int main(int argc, char * argv)
{pthread_t pid, cid;srand(time(NULL));pthread_create(&pid, NULL, producer, NULL);pthread_create(&cid, NULL, consumer, NULL);pthread_join(pid, NULL);pthread_join(cid, NULL);return 0;
}
信號量,是相對折中的一種處理方式,既能保證同步,數據不混亂,又能提高線程并發。
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
參2:abs_timeout采用的是絕對時間。
【練習】:使用信號量完成線程間同步,模擬生產者,消費者問題。
/*信號量實現生產者消費者問題*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>#define NUM 5int queue[NUM]; //全局數組實現環形隊列
sem_t blank_number, product_number; //空格子信號量,產品信號量void *producer(void *arg)
{int i = 0;while(1) {sem_wait(&blank_number); //生產者將空格子數--,為0則阻塞等待queue[i] = rand() % 1000 + 1; //生產一個產品printf("----Produce----%d\n", queue[i]);sem_post(&product_number); //將產品數++i = (i+1) % NUM; //借助下標實現環形sleep(rand() % 3); } return NULL;
}void *consumer(void *arg)
{int i = 0;while(1){sem_wait(&product_number); //消費者將產品數--,為0則阻塞等待printf("--Consume---%d\n", queue[i]);queue[i] = 0; //消費一個產品sem_post(&blank_number); //消費掉以后,將空格子數++i = (i+1) % NUM; //借助下標實現環形sleep(rand() % 3); } return NULL;
}int main()
{pthread_t pid, cid;sem_init(&blank_number, 0, NUM); //初始化空格子信號量為5sem_init(&product_number, 0, 0); //產品數為0pthread_create(&pid, NULL, producer, NULL);pthread_create(&cid, NULL, consumer, NULL);pthread_join(pid, NULL);pthread_join(cid, NULL);sem_destroy(&blank_number);sem_destroy(&product_number);return 0;
}
所以有:
T生產者主函數 {sem_wait(S空);生產...sem_post(S滿)
}T消費者主函數 {sem_wait(S滿);消費...sem_post(S空)
}
【作業】:結合生產者消費者信號量模型,揣摩sem_timedwait函數作用。編程實現,一個線程讀用戶輸入,另一個線程打印“hello world”。如果用戶無輸入,則每隔5秒向屏幕打印一個“hello world”;如果用戶有輸入,立刻打印“hello world”到屏幕。
進程間也可以使用互斥鎖,來達到同步的目的。但應在pthread_mutex_init初始化之前,修改其屬性為進程間共享。mutex的屬性修改函數主要有以下幾個。
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
進程間mutex示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/wait.h>struct mt {int num;pthread_mutex_t mutex;pthread_mutexattr_t mutexattr;
};int main()
{int i;struct mt *mm;pid_t pid;mm = mmap(NULL, sizeof(*mm), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);memset(mm, 0, sizeof(*mm));pthread_mutexattr_init(&mm->mutexattr); //初始化mutex屬性對象pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED); //修改屬性為進程間共享pthread_mutex_init(&mm->mutex, &mm->mutexattr); //初始化一把mutex鎖pid = fork();if(pid == 0){for(i = 0; i < 10; i++){pthread_mutex_lock(&mm->mutex);(mm->num)++;printf("-Child------------num++ %d\n", mm->num);pthread_mutex_unlock(&mm->mutex);sleep(1);}} else if(pid > 0){for(i = 0; i < 10; i++){sleep(1);pthread_mutex_lock(&mm->mutex);mm->num+=2;printf("-------parent-----num+=2 %d\n", mm->num);pthread_mutex_unlock(&mm->mutex);}wait(NULL);}pthread_mutexattr_destroy(&mm->mutexattr); //銷毀mutex屬性對象pthread_mutex_destroy(&mm->mutex); //銷毀mutexmunmap(mm,sizeof(*mm)); //釋放映射區return 0;
}
參3:
struct flock {...short l_type; /* 鎖的類型: F_RDLCK, F_WRLCK, F_UNLCK */short l_whence; /* 偏移位置: SEEK_SET, SEEK_CUR, SEEK_END */off_t l_start; /* 起始偏移:1000*/off_t l_len; /* 長度:0表示整個文件加鎖 */pid_t l_pid; /* 持有該鎖的進程ID:F_GETLK, F_OFD_GETLK */...
};
進程間文件鎖示例
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>void sys_err(char *str){perror(str);exit(1);
}int main(int argc, char *argv[])
{int fd;struct flock f_lock;if(argc < 2){printf("./a.out filename\n");exit(1);}if((fd = open(argv[1], O_RDWR)) < 0)sys_err("open");f_lock.l_type = F_WRLCK; //選用寫鎖//f_lock.l_type = F_RDLCK; //選用讀鎖f_lock.l_whence = SEEK_SET;f_lock.l_start = 0;f_lock.l_len = 0; //0表示整個文件加鎖fcntl(fd, F_SETLKW, &f_lock);printf("get flock\n");sleep(10);f_lock.l_type = F_UNLCK;fcntl(fd, F_SETLKW, &f_lock);printf("un flock\n");close(fd);return 0;
}
void *tfn(void *arg)
,使用參數來表示線程編號:int i = (int)arg;
5支筷子,在邏輯上形成環,分別對應5個哲學家。
A B C D E
0 1 2 3 4
所以有:
if(i == 4)left = i, right = 0;
elseleft = i, right = i + 1;
所以以上if else語句應改為
if(i == 4)left = 0, right = i;
elseleft = i, right = i + 1;
而后,首先讓哲學家嘗試加左手鎖:
while(1){pthread_mutex_lock(&m[left]); 如果加鎖成功,函數返回再加右手鎖,如果失敗,應立即釋放左手鎖,等待。若左右手都加鎖成功 --> 吃 --> 吃完 --> 釋放鎖(應先釋放右手、再釋放左手,是加鎖順序的逆序)
}
子進程中:
if(i == 4)left = 0, right = 4;
elseleft = i, right = i + 1;while(1){使用sem_wait(&s[left])鎖左手,嘗試鎖右手,若成功 --> 吃;若不成功 --> 將左手鎖釋放。吃完后,先釋放右手鎖,再釋放左手鎖。
}
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态