Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在执行公共任务时等待多个线程?_C#_Multithreading_Asynchronous_Async Await_Thread Synchronization - Fatal编程技术网

C# 如何在执行公共任务时等待多个线程?

C# 如何在执行公共任务时等待多个线程?,c#,multithreading,asynchronous,async-await,thread-synchronization,C#,Multithreading,Asynchronous,Async Await,Thread Synchronization,我有多个线程并行执行API调用。每当jwt令牌过期时,我希望所有线程等待,直到调用刷新令牌API并返回有效的更新jwt令牌。我有一个singleton类,它有一个刷新令牌方法,该方法将进行调用并更新令牌。我如何确保所有其他线程都将等待令牌获取完成 public class JWTTokenManager { private static JWTTokenManager _tokenManager; private string _token;

我有多个线程并行执行API调用。每当jwt令牌过期时,我希望所有线程等待,直到调用刷新令牌API并返回有效的更新jwt令牌。我有一个singleton类,它有一个刷新令牌方法,该方法将进行调用并更新令牌。我如何确保所有其他线程都将等待令牌获取完成

public class JWTTokenManager
    {
        private static JWTTokenManager _tokenManager;
        private string _token;
        private bool _refreshingToken;

        public static JWTTokenManager GetManager()
        {
            if (_tokenManager == null)
                _tokenManager = new JWTTokenManager();
            return _tokenManager;
        }

        public void UpdateToken(string token)
        {
            _token = token;
        }

        public string GetToken()
        {
            return _token;
        }

        public async Task<bool> ValidateRefreshTocken()
        {
            UserInfo userdata = JsonConvert.DeserializeObject<UserInfo>(GetUserInfo(_token), new Helper.DefaultJsonSetting());
            if (!string.IsNullOrWhiteSpace(userdata.Exp) && TokenExpired(long.Parse(userdata.Exp)))
            {
                _refreshingToken = true;
                JWTToken jwtToken = Database.DBService.GetDB().FetchJWTToken();
                RefreshToken requestRefresh = new RefreshToken
                {
                    ExpiredTocken = jwtToken.Token,
                    RefreshTocken = jwtToken.RefreshToken
                };
                HttpClient httpClient = CloudService.GetCloudService().GetHttpClient();
                HttpResponseMessage response = await httpClient.PostAsync($"account/v1/tokenRefresh", new StringContent(JsonConvert.SerializeObject(requestRefresh), Encoding.UTF8, "application/json"));
                bool responseStatus = await ParseTokenResponseAsync(response);
                _refreshingToken = false;
                return responseStatus;
            }
            else
            {
                return true;
            }
        }

        private string GetUserInfo(string key)
        {
            string[] base64Url = key.Split('.');
            if (base64Url.Length > 1)
            {
                string userinfo = base64Url[1];
                userinfo = userinfo.Replace(" ", "+");
                int mod4 = userinfo.Length % 4;
                if (mod4 > 0)
                {
                    userinfo += new string('=', 4 - mod4);
                }
                var base64EncodedBytes = System.Convert.FromBase64String(userinfo);
                return Encoding.UTF8.GetString(base64EncodedBytes);
            }
            else
            {
                return "";
            }
        }

        public bool TokenExpired(long unixTimeStamp)
        {
            DateTime tokenExpiryDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            tokenExpiryDateTime = tokenExpiryDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
            DateTime currentDateTime = DateTime.Now;
            return DateTime.Compare(tokenExpiryDateTime, currentDateTime) <= 0;
        }

        public async Task<bool> ParseTokenResponseAsync(HttpResponseMessage httpResponse)
        {
            if (httpResponse.IsSuccessStatusCode == true)
            {
                string responseString = await httpResponse.Content.ReadAsStringAsync();
                Newtonsoft.Json.Linq.JObject responsedataObject = Newtonsoft.Json.Linq.JObject.Parse(responseString);
                string token = responsedataObject["data"]["token"].ToString();
                string refreshToken = responsedataObject["data"]["refreshToken"].ToString();
                _token = token;
                JWTToken updatedToken = new JWTToken()
                {
                    Token = _token,
                    RefreshToken = refreshToken
                };
                Database.DBService.GetDB().InsertOrUpdateJWTToken(updatedToken);
                return true;
            }
            else
            {
                return false;
            }
        }
    }
public class CloudService
{
    private const int TIME_OUT = 50;
    private const int HTTP_GET = 0;
    private const int HTTP_PUT = 1;
    private const int HTTP_POST = 2;
    private const int HTTP_DELETE = 3;

    private static CloudService _serviceInstance;

    public static CloudService GetCloudService()
    {
        if (_serviceInstance == null)
            _serviceInstance = new CloudService();
        return _serviceInstance;
    }

    private async Task<HttpResponseMessage> ExecuteHttpTask(int taskType, string url, StringContent content = null)
    {
        HttpClient httpClient = GetHttpClient();
        switch (taskType)
        {
            case HTTP_GET:
                return await httpClient.GetAsync(url);
            case HTTP_PUT:
                return await httpClient.PutAsync(url, content);
            case HTTP_POST:
                return await httpClient.PostAsync(url, content);
            case HTTP_DELETE:
                return await httpClient.DeleteAsync(url);
            default:
                return null;
        }
    }

    public async Task<Response> HTTPTask(string url, int taskType, StringContent content = null, bool login = false)
    {
                bool refreshTocken = await JWTTokenManager.GetManager().ValidateRefreshTocken();

        Response httpResponse = new Response();
        try
        {
            HttpResponseMessage response = await ExecuteHttpTask(taskType, url, content);

            string responseString = await response.Content.ReadAsStringAsync();
            if (!response.IsSuccessStatusCode)
                httpResponse.status = "error";
            else
                httpResponse.status = "data";
            httpResponse.data = ParseResponseData(httpResponse.status, responseString);
        }
        catch (Exception e)
        {
            httpResponse = GenericErrorResponse(e.Message);
        }
        return httpResponse;
    }

    public async Task<Response> GetSectionAsync(string id)
    {
        string url = $"catalog/v2/homepageSections/{id}?order-by=name,asc";
        return await HTTPTask(url, Constants.HTTP_GET);
    }

    public async Task<Response> GetProductAsync(string id)
    {
        string url = $"catalog/v2/products/{id}";
        return await HTTPTask(url, Constants.HTTP_GET);
    }

    public async Task<Response> GetCourseDetailsAsync(string id)
    {
        string url = $"catalog/v2/products/{id}/courseDetails";
        return await HTTPTask(url, Constants.HTTP_GET);
    }

}
公共类JWTTokenManager
{
私有静态JWTTokenManager\u tokenManager;
私有字符串\u令牌;
私立学校进修课程;
公共静态JWTTokenManager GetManager()
{
if(_tokenManager==null)
_tokenManager=新的JWTTokenManager();
返回"标记管理器;;
}
公共void UpdateToken(字符串标记)
{
_令牌=令牌;
}
公共字符串GetToken()
{
返回令牌;
}
公共异步任务ValidateRefreshTocken()
{
UserInfo userdata=JsonConvert.DeserializeObject(GetUserInfo(_标记),new Helper.DefaultJsonSetting());
如果(!string.IsNullOrWhiteSpace(userdata.Exp)&&TokenExpired(long.Parse(userdata.Exp)))
{
_refreshingToken=true;
JWTToken JWTToken=Database.DBService.GetDB().FetchJWTToken();
RefreshToken requestRefresh=新的RefreshToken
{
expiredToken=jwtToken.Token,
RefreshTocken=jwtToken.RefreshToken
};
HttpClient HttpClient=CloudService.GetCloudService().GetHttpClient();
HttpResponseMessage response=等待httpClient.PostAsync($“account/v1/tokenRefresh”,新的StringContent(JsonConvert.SerializeObject(requestRefresh),Encoding.UTF8,“application/json”);
bool responseStatus=wait-ParseTokenResponseAsync(响应);
_refreshingToken=false;
返回响应状态;
}
其他的
{
返回true;
}
}
私有字符串GetUserInfo(字符串键)
{
字符串[]base64Url=key.Split('.');
如果(base64Url.Length>1)
{
字符串userinfo=base64Url[1];
userinfo=userinfo.Replace(“,“+”);
int mod4=userinfo.Length%4;
如果(mod4>0)
{
userinfo+=新字符串('=',4-mod4);
}
var base64EncodedBytes=System.Convert.FromBase64String(userinfo);
返回Encoding.UTF8.GetString(base64EncodedBytes);
}
其他的
{
返回“”;
}
}
公共bool令牌过期(长unixTimeStamp)
{
DateTime令牌ExpireyDateTime=新的日期时间(1970,1,1,0,0,0,0,DateTimeKind.Utc);
tokenExpiryDateTime=tokenExpiryDateTime.AddSeconds(unixTimeStamp.ToLocalTime();
DateTime currentDateTime=DateTime.Now;
返回日期时间。比较(tokenExpiryDateTime、currentDateTime)1)
{
字符串userinfo=base64Url[1];
userinfo=userinfo.Replace(“,“+”);
int mod4=userinfo.Length%4;
如果(mod4>0)
{
userinfo+=新字符串('=',4-mod4);
}
var base64EncodedBytes=System.Convert.FromBase64String(userinfo);
返回Encoding.UTF8.GetString(base64EncodedBytes);
}
其他的
{
返回“”;
}
}
公共bool令牌过期(长unixTimeStamp)
{
DateTime令牌ExpireyDateTime=新的日期时间(1970,1,1,0,0,0,0,DateTimeKind.Utc);
tokenExpiryDateTime=tokenExpiryDateTime.AddSeconds(unixTimeStamp.ToLocalTime();
DateTime currentDateTime=DateTime.Now;
return DateTime.Compare(tokenexpireydatetime,currentDateTime)您可以使用a。假设您有三个线程a、B(并行调用api调用)和C(执行令牌刷新)


您应该让
JWTTokenManager
返回一个令牌,而不是它需要一个令牌

如果令牌有效,它将返回带有有效令牌的已完成任务,如果无效,它将返回在检索令牌时将完成的任务。同一任务可由多个并发线程等待

public class JWTTokenManager
{
    private Task<string> tokenTask;
    private readonly object sync = new object();

    public Task<string> GetTokenAsync()
    {
        lock (sync)
        {
            if (tokenTask.IsCompleted && !IsTokenValid(tokenTask.Result))
            {
                tokenTask = GetNewTokenAsync();
            }

            return tokenTask;
        }
    }
}
公共类JWTTokenManager
{
私有任务标记任务;
私有只读对象同步=新对象();
公共任务GetTokenAsync()
{
锁定(同步)
{
if(tokenTask.IsCompleted&!IsTokenValid(tokenTask.Result))
{
tokenTask=GetNewTokenAsync();
}
返回任务;
}
}
}
无锁版本:

public class JWTTokenManager
{
    private Task<string> tokenTask;
    private readonly object sync = new object();

    public Task<string> GetTokenAsync()
    {
        var currentTokenTask = Volatile.Read(ref tokenTask);

        if (currentTokenTask .IsCompleted && !IsTokenValid(currentTokenTask .Result))
        {
            currentTokenTask = GetNewTokenAsync();
            Volatile.Write(ref tokenTask, currentTokenTask);
        }

        return currentTokenTask ;
    }
}
公共类JWTTokenManager
{
私有任务标记任务;
私有只读对象同步=新对象();
公共任务GetTokenAsync()
{
var currentTokenTask=Volatile.Read(ref-tokenTask);
if(currentTokenTask.IsCompleted&!IsTokenValid(currentTokenTask.Result))
{
currentTokenTask=GetNewTokenAsync();
Volatile.Write(ref-tokenTask,currentTokenTask);
}
返回当前任务;
}
}

Look for wait all Unrelated:你的Singleton实现不是线程安全的。你确定没有任何问题吗?@Fildor请你详细说明一下。理论上,JWTTokenManager可能不止一个实例。这可能会导致问题。特别是当你试图同步你的thr时eads。很可能您忽略了隐式线程竞赛错误。您无法确保令牌不会在线程竞赛失败时过期
public class JWTTokenManager
{
    private Task<string> tokenTask;
    private readonly object sync = new object();

    public Task<string> GetTokenAsync()
    {
        lock (sync)
        {
            if (tokenTask.IsCompleted && !IsTokenValid(tokenTask.Result))
            {
                tokenTask = GetNewTokenAsync();
            }

            return tokenTask;
        }
    }
}
public class JWTTokenManager
{
    private Task<string> tokenTask;
    private readonly object sync = new object();

    public Task<string> GetTokenAsync()
    {
        var currentTokenTask = Volatile.Read(ref tokenTask);

        if (currentTokenTask .IsCompleted && !IsTokenValid(currentTokenTask .Result))
        {
            currentTokenTask = GetNewTokenAsync();
            Volatile.Write(ref tokenTask, currentTokenTask);
        }

        return currentTokenTask ;
    }
}