Feeds:
文章
迴響

Archive for 2010 年 07 月

從我開始大量將手頭的 PDF 佈署到 Google Docs 之後,常常發現開啟 n 個 PDF 之後,PDF 文件開啟都是空文件,無法正常顯示(獲得 HTTP 400 Bad Request),不知道這個是不是 Google Docs 的本身限制。不過如果你有多種瀏覽器,你會發現假設 Firefox 已達到 PDF 開啟數量限制,此時用 Chrome 去開啟 PDF 則仍可正常顯示,不過當你開啟 n 個 PDF 之後還是遇到同樣的問題。因此可以排除是瀏覽器造成。

再來是當已經無法開啟”新”的PDF文件時,開啟”舊”(也就是曾經開過且正常)文件卻可正常顯示,從 HTTP 工具觀察,舊文件可觀看是因為 Cache。不過,當我清除 Cache 之後,舊文件還是可以正常看,所以有無 Cache 並不會影響 PDF 是否能開啟。

然後如果我登出 Google Docs 帳戶再重新登入,新PDF文件還是無法開啟。舊文件依然正常。但是如果我清除 Cookie 再重新登入,就能夠重新開啟新的 PDF 文件,所以我的結論就是 Google Docs 在 Cookie 應該有紀錄你開過幾份文件,並且在超過之後就不允許你繼續使用。

繼續追查下去發現,有一個隸屬 doc.google.com 網域的 gvchan 的 cookie,只要刪掉一切就都正常啦 XDDDD

Read Full Post »

今天嘗試透過 ADO.NET 的 SqlConnection 連線到 SQL Server Express,原本我用在 SQL Server 2005 的連線字串是

Data Source=localhost;Initial Catalog=DBName;User ID=uid;Password=pwd;Pooling=True;Max Pool Size=300

可是怎麼連都出現

“A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 – Could not open a connection to SQL Server)”

後來查到這篇文章才知道,SQL Server 2008 Express 連線字串的 DataSource 要用

Data Source=.SqlExpress;Initial Catalog=DBName;User ID=uid;Password=pwd;Pooling=True;Max Pool Size=300

真是 OOXX 為什麼不統一就好了 ~

Read Full Post »

[C#]多執行緒一寫多讀

最近一直遇到多執行緒一寫多讀的問題,之前在腦中有想過大略的解法,直到今天才嘗試實作。在說明我的實作之前,我先來描述一下問題

需求:有一個包含多個資料的容器用來快取資料,但是這些資料在一段時間後需要更新,而更新資料又需要花一段時間,此時如何在讀取影響範圍最小情況下更新快取資料

一開始最直覺的解法就是直接用 lock,如:

if (Timeout ){
    lock(cache ){
       cache = …    
    }
}
return cache;

可是這種寫法的問題在於 lock 發生時,其他執行緒無法進行讀寫,所以不是我們想要的。

後來我想到讀寫鎖(ReadWriteLock),於是我嘗試改寫成

if (Timeout){
    rwl.AcquireWriterLock(-1);
    try{
           cache = …
    }finally{
        rwl.ReleaseWriterLock();
    } 
}
return cache

最後發現結果與 lock 一樣,所以,即便用 ReadWriteLock 在取得寫鎖定時,其他執行緒仍會無法讀取。

於是我用了一個旗標來解決這個問題,如下:

if (!IsQuerying && Timeout){
    rwl.AcquireReaderLock();
    if(!IsQuerying){
        IsQuerying = true;
        rwl.ReleaseReaderLock();

        // 處理 cache 資料

       rwl.AcquireWriteLock();
       cache = …
       IsQuerying = false;
       rwl.ReleaseWriteLock();
    }else{
        rwl.ReleaseReaderLock();
    }   
}
return cache;

透過 IsQuerying 旗標+ReaderLock 來避免其他執行緒進入更新程序,然後釋放鎖定使其他執行緒仍然能夠繼續讀取 cache 資料,直到 cache 必要資料處理完成之後,再取得 WriterLock 來避免其他執行緒再更新完成之前再次讀取資料,更新資料和 IsQuerying 旗標後再釋放 WriterLock 即可。

以下是我的模擬程式

using System;
using System.Threading;
using System.Collections.Generic;

public class Split
{
    class Data {
        public int v = 100;
    }

    class A{
        public static DateTime Expired = DateTime.Now;
        private static ReaderWriterLock rwl = new ReaderWriterLock();
        private static bool IsQuerying = false;
       
        public static int rndValue() {
            var rnd = new Random((int)DateTime.Now.Ticks);
            return rnd.Next(1, 10);
        }

        private List<Data> datalist = null;
        public List<Data> DataList{
            get {
                //1.檢查是否過期 & 查詢中...
                if (!IsQuerying && (DateTime.Now - Expired).Seconds > 3) {

                    // 2. Double Check 避免其他 Thread 覆寫狀態
                       rwl.AcquireReaderLock(-1);
                    if (!IsQuerying) {
                        // 3. 設定為查詢中
                        IsQuerying = true;

                        // 4. 釋放讀取狀態
                        rwl.ReleaseReaderLock();

                        // 5. 建立新的資料
                        var new_list = new List<Data>();
                        new_list.Add(new Data { v = rndValue() });
                        new_list.Add(new Data { v = rndValue() });
                        new_list.Add(new Data { v = rndValue() });
                        new_list.Add(new Data { v = rndValue() });
                        new_list.Add(new Data { v = rndValue() });    
Thread.Sleep(2000);
// 6. 取得寫入鎖定 & 寫入資料 & 更新狀態 & 釋放鎖定 rwl.AcquireWriterLock(-1); this.datalist = new_list; Expired = DateTime.Now; // 先更新時間 IsQuerying = false; rwl.ReleaseWriterLock(); } else { // 如果真的發生意外,釋放鎖定避免死結 rwl.ReleaseReaderLock(); } } return datalist; } } public A() { datalist = new List<Data>(); datalist.Add(new Data()); datalist.Add(new Data()); datalist.Add(new Data()); datalist.Add(new Data()); datalist.Add(new Data()); } private static A a = new A(); public static A getInstance() { return a; } } class OneWriteMoreRead { public static void Task(object xx) { while (true) { Thread.Sleep(100); var x = A.getInstance(); var sum = 0; foreach (var data in x.DataList) { sum += data.v; } Console.WriteLine(String.Format("{0}=>{1}", xx, sum)); } } public void Demo() { for (var i = 0; i < 5; ++i) { (new Thread(new ParameterizedThreadStart(Task))).Start(i); } Console.ReadKey(); } } public static void Main(String[] args) { (new OneWriteMoreRead()).Demo(); } }

 

執行結果:

 

不太確定我對 ReadWriteLock 的理解是否正確,如果有錯或有更好的寫法請告訴我,感激~

Read Full Post »